diff options
Diffstat (limited to '')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCPeerConnection-addTransceiver.https.html | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCPeerConnection-addTransceiver.https.html b/testing/web-platform/tests/webrtc/RTCPeerConnection-addTransceiver.https.html new file mode 100644 index 0000000000..3fd83a76fe --- /dev/null +++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-addTransceiver.https.html @@ -0,0 +1,441 @@ +<!doctype html> +<meta charset=utf-8> +<title>RTCPeerConnection.prototype.addTransceiver</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="RTCPeerConnection-helper.js"></script> +<script> + 'use strict'; + + // Test is based on the following editor draft: + // https://rawgit.com/w3c/webrtc-pc/cc8d80f455b86c8041d63bceb8b457f45c72aa89/webrtc.html + + /* + 5.1. RTCPeerConnection Interface Extensions + + partial interface RTCPeerConnection { + sequence<RTCRtpSender> getSenders(); + sequence<RTCRtpReceiver> getReceivers(); + sequence<RTCRtpTransceiver> getTransceivers(); + RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, + optional RTCRtpTransceiverInit init); + ... + }; + + dictionary RTCRtpTransceiverInit { + RTCRtpTransceiverDirection direction = "sendrecv"; + sequence<MediaStream> streams; + sequence<RTCRtpEncodingParameters> sendEncodings; + }; + + enum RTCRtpTransceiverDirection { + "sendrecv", + "sendonly", + "recvonly", + "inactive" + }; + + 5.2. RTCRtpSender Interface + + interface RTCRtpSender { + readonly attribute MediaStreamTrack? track; + ... + }; + + 5.3. RTCRtpReceiver Interface + + interface RTCRtpReceiver { + readonly attribute MediaStreamTrack track; + ... + }; + + 5.4. RTCRtpTransceiver Interface + + interface RTCRtpTransceiver { + readonly attribute DOMString? mid; + [SameObject] + readonly attribute RTCRtpSender sender; + [SameObject] + readonly attribute RTCRtpReceiver receiver; + readonly attribute boolean stopped; + readonly attribute RTCRtpTransceiverDirection direction; + readonly attribute RTCRtpTransceiverDirection? currentDirection; + ... + }; + + Note + While addTrack checks if the MediaStreamTrack given as an argument is + already being sent to avoid sending the same MediaStreamTrack twice, + the other ways do not, allowing the same MediaStreamTrack to be sent + several times simultaneously. + */ + + /* + 5.1. addTransceiver + 3. If the first argument is a string, let it be kind and run the following steps: + 1. If kind is not a legal MediaStreamTrack kind, throw a TypeError. + */ + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + assert_idl_attribute(pc, 'addTransceiver'); + assert_throws_js(TypeError, () => pc.addTransceiver('invalid')); + }, 'addTransceiver() with string argument as invalid kind should throw TypeError'); + + /* + 5.1. addTransceiver + The initial value of mid is null. + + 3. If the dictionary argument is present, let direction be the value of the + direction member. Otherwise let direction be sendrecv. + 4. If the first argument is a string, let it be kind and run the following steps: + 2. Let track be null. + 8. Create an RTCRtpSender with track, streams and sendEncodings and let + sender be the result. + 9. Create an RTCRtpReceiver with kind and let receiver be the result. + 10. Create an RTCRtpTransceiver with sender, receiver and direction, and let + transceiver be the result. + 11. Add transceiver to connection's set of transceivers. + + 5.2. RTCRtpSender Interface + Create an RTCRtpSender + 2. Set sender.track to track. + + 5.3. RTCRtpReceiver Interface + Create an RTCRtpReceiver + 2. Let track be a new MediaStreamTrack object [GETUSERMEDIA]. The source of + track is a remote source provided by receiver. + 3. Initialize track.kind to kind. + 5. Initialize track.label to the result of concatenating the string "remote " + with kind. + 6. Initialize track.readyState to live. + 7. Initialize track.muted to true. + 8. Set receiver.track to track. + + 5.4. RTCRtpTransceiver Interface + Create an RTCRtpTransceiver + 2. Set transceiver.sender to sender. + 3. Set transceiver.receiver to receiver. + 4. Let transceiver have a [[Direction]] internal slot, initialized to direction. + 5. Let transceiver have a [[CurrentDirection]] internal slot, initialized + to null. + 6. Set transceiver.stopped to false. + */ + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + assert_idl_attribute(pc, 'addTransceiver'); + + const transceiver = pc.addTransceiver('audio'); + assert_true(transceiver instanceof RTCRtpTransceiver, + 'Expect transceiver to be instance of RTCRtpTransceiver'); + + assert_equals(transceiver.mid, null); + assert_equals(transceiver.stopped, false); + assert_equals(transceiver.direction, 'sendrecv'); + assert_equals(transceiver.currentDirection, null); + + assert_array_equals([transceiver], pc.getTransceivers(), + `Expect added transceiver to be the only element in connection's list of transceivers`); + + const sender = transceiver.sender; + + assert_true(sender instanceof RTCRtpSender, + 'Expect sender to be instance of RTCRtpSender'); + + assert_equals(sender.track, null); + + assert_array_equals([sender], pc.getSenders(), + `Expect added sender to be the only element in connection's list of senders`); + + const receiver = transceiver.receiver; + assert_true(receiver instanceof RTCRtpReceiver, + 'Expect receiver to be instance of RTCRtpReceiver'); + + const track = receiver.track; + assert_true(track instanceof MediaStreamTrack, + 'Expect receiver.track to be instance of MediaStreamTrack'); + + assert_equals(track.kind, 'audio'); + assert_equals(track.readyState, 'live'); + assert_equals(track.muted, true); + + assert_array_equals([receiver], pc.getReceivers(), + `Expect added receiver to be the only element in connection's list of receivers`); + + }, `addTransceiver('audio') should return an audio transceiver`); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + assert_idl_attribute(pc, 'addTransceiver'); + + const transceiver = pc.addTransceiver('video'); + assert_true(transceiver instanceof RTCRtpTransceiver, + 'Expect transceiver to be instance of RTCRtpTransceiver'); + + assert_equals(transceiver.mid, null); + assert_equals(transceiver.stopped, false); + assert_equals(transceiver.direction, 'sendrecv'); + + assert_array_equals([transceiver], pc.getTransceivers(), + `Expect added transceiver to be the only element in connection's list of transceivers`); + + const sender = transceiver.sender; + + assert_true(sender instanceof RTCRtpSender, + 'Expect sender to be instance of RTCRtpSender'); + + assert_equals(sender.track, null); + + assert_array_equals([sender], pc.getSenders(), + `Expect added sender to be the only element in connection's list of senders`); + + const receiver = transceiver.receiver; + assert_true(receiver instanceof RTCRtpReceiver, + 'Expect receiver to be instance of RTCRtpReceiver'); + + const track = receiver.track; + assert_true(track instanceof MediaStreamTrack, + 'Expect receiver.track to be instance of MediaStreamTrack'); + + assert_equals(track.kind, 'video'); + assert_equals(track.readyState, 'live'); + assert_equals(track.muted, true); + + assert_array_equals([receiver], pc.getReceivers(), + `Expect added receiver to be the only element in connection's list of receivers`); + + }, `addTransceiver('video') should return a video transceiver`); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' }); + assert_equals(transceiver.direction, 'sendonly'); + }, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + const transceiver = pc.addTransceiver('audio', { direction: 'inactive' }); + assert_equals(transceiver.direction, 'inactive'); + }, `addTransceiver() with direction inactive should have result transceiver.direction be the same`); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + assert_idl_attribute(pc, 'addTransceiver'); + assert_throws_js(TypeError, () => + pc.addTransceiver('audio', { direction: 'invalid' })); + }, `addTransceiver() with invalid direction should throw TypeError`); + + /* + 5.1. addTransceiver + 5. If the first argument is a MediaStreamTrack , let it be track and let + kind be track.kind. + */ + promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + const stream = await getNoiseStream({audio: true}); + t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); + const [track] = stream.getTracks(); + const transceiver = pc.addTransceiver(track); + const { sender, receiver } = transceiver; + + assert_true(sender instanceof RTCRtpSender, + 'Expect sender to be instance of RTCRtpSender'); + + assert_true(receiver instanceof RTCRtpReceiver, + 'Expect receiver to be instance of RTCRtpReceiver'); + + assert_equals(sender.track, track, + 'Expect sender.track should be the track that is added'); + + const receiverTrack = receiver.track; + assert_true(receiverTrack instanceof MediaStreamTrack, + 'Expect receiver.track to be instance of MediaStreamTrack'); + + assert_equals(receiverTrack.kind, 'audio', + `receiver.track should have the same kind as added track's kind`); + + assert_equals(receiverTrack.readyState, 'live'); + assert_equals(receiverTrack.muted, true); + + assert_array_equals([transceiver], pc.getTransceivers(), + `Expect added transceiver to be the only element in connection's list of transceivers`); + + assert_array_equals([sender], pc.getSenders(), + `Expect added sender to be the only element in connection's list of senders`); + + assert_array_equals([receiver], pc.getReceivers(), + `Expect added receiver to be the only element in connection's list of receivers`); + + }, 'addTransceiver(track) should have result with sender.track be given track'); + + promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + const stream = await getNoiseStream({audio: true}); + t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); + const [track] = stream.getTracks(); + const transceiver1 = pc.addTransceiver(track); + const transceiver2 = pc.addTransceiver(track); + + assert_not_equals(transceiver1, transceiver2); + + const sender1 = transceiver1.sender; + const sender2 = transceiver2.sender; + + assert_not_equals(sender1, sender2); + assert_equals(transceiver1.sender.track, track); + assert_equals(transceiver2.sender.track, track); + + const transceivers = pc.getTransceivers(); + assert_equals(transceivers.length, 2); + assert_true(transceivers.includes(transceiver1)); + assert_true(transceivers.includes(transceiver2)); + + const senders = pc.getSenders(); + assert_equals(senders.length, 2); + assert_true(senders.includes(sender1)); + assert_true(senders.includes(sender2)); + + }, 'addTransceiver(track) multiple times should create multiple transceivers'); + + /* + 5.1. addTransceiver + 6. Verify that each rid value in sendEncodings is composed only of + case-sensitive alphanumeric characters (a-z, A-Z, 0-9) up to a maximum + of 16 characters. If one of the RIDs does not meet these requirements, + throw a TypeError. + */ + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + assert_idl_attribute(pc, 'addTransceiver'); + + assert_throws_js(TypeError, () => + pc.addTransceiver('video', { + sendEncodings: [{ + rid: '@Invalid!' + }] + })); + }, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError'); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + assert_idl_attribute(pc, 'addTransceiver'); + + assert_throws_js(TypeError, () => + pc.addTransceiver('audio', { + sendEncodings: [{ + rid: 'a'.repeat(17) + }] + })); + }, 'addTransceiver() with rid longer than 16 characters should throw TypeError'); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.addTransceiver('audio', { + sendEncodings: [{ + rid: 'foo' + }] + }); + }, `addTransceiver() with valid rid value should succeed`); + + test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + pc.addTransceiver('video', { + sendEncodings: [{ + dtx: 'enabled', + active: false, + ptime: 5, + maxBitrate: 8, + maxFramerate: 25, + rid: 'foo' + }] + }); + }, `addTransceiver() with valid sendEncodings should succeed`); + + /* + TODO + 5.1. addTransceiver + - Adding a transceiver will cause future calls to createOffer to add a media + description for the corresponding transceiver, as defined in [JSEP] + (section 5.2.2.). + + - Setting a new RTCSessionDescription may change mid to a non-null value, + as defined in [JSEP] (section 5.5. and section 5.6.). + + 1. If the dictionary argument is present, and it has a streams member, let + streams be that list of MediaStream objects. + + 5.2. RTCRtpSender Interface + Create an RTCRtpSender + 3. Let sender have an [[associated MediaStreams]] internal slot, representing + a list of MediaStream objects that the MediaStreamTrack object of this + sender is associated with. + + 4. Set sender's [[associated MediaStreams]] slot to streams. + + 5. Let sender have a [[send encodings]] internal slot, representing a list + of RTCRtpEncodingParameters dictionaries. + + 6. If sendEncodings is given as input to this algorithm, and is non-empty, + set the [[send encodings]] slot to sendEncodings. Otherwise, set it to a + list containing a single RTCRtpEncodingParameters with active set to true. + + 5.3. RTCRtpReceiver Interface + Create an RTCRtpReceiver + 4. If an id string, id, was given as input to this algorithm, initialize + track.id to id. (Otherwise the value generated when track was created + will be used.) + + Tested in RTCPeerConnection-onnegotiationneeded.html + 5.1. addTransceiver + 12. Update the negotiation-needed flag for connection. + + Out of Scope + 5.1. addTransceiver + 8. If sendEncodings is set, then subsequent calls to createOffer will be + configured to send multiple RTP encodings as defined in [JSEP] + (section 5.2.2. and section 5.2.1.). + + When setRemoteDescription is called with a corresponding remote + description that is able to receive multiple RTP encodings as defined + in [JSEP] (section 3.7.), the RTCRtpSender may send multiple RTP + encodings and the parameters retrieved via the transceiver's + sender.getParameters() will reflect the encodings negotiated. + + 9. This specification does not define how to configure createOffer to + receive multiple RTP encodings. However when setRemoteDescription is + called with a corresponding remote description that is able to send + multiple RTP encodings as defined in [JSEP], the RTCRtpReceiver may + receive multiple RTP encodings and the parameters retrieved via the + transceiver's receiver.getParameters() will reflect the encodings + negotiated. + + Coverage Report + Tested Not-Tested Non-Testable Total + addTransceiver 14 1 3 18 + Create Sender 3 4 0 7 + Create Receiver 8 1 0 9 + Create Transceiver 7 0 0 7 + + Total 32 6 3 41 + */ +</script> |