| <!doctype html> |
| <html> |
| <head> |
| <meta charset=utf-8> |
| <title>RTCRtpScriptTransformer.generateKeyFrame tests</title> |
| <meta name='timeout' content='long'> |
| <script src='/resources/testharness.js'></script> |
| <script src='/resources/testharnessreport.js'></script> |
| <script src=/resources/testdriver.js></script> |
| <script src=/resources/testdriver-vendor.js></script> |
| <script src='../mediacapture-streams/permission-helper.js'></script> |
| </head> |
| <body> |
| <video id='video1' autoplay></video> |
| <video id='video2' autoplay></video> |
| <script src ='routines.js'></script> |
| <script src ='../webrtc/simulcast/simulcast.js'></script> |
| <script src ='../webrtc/RTCPeerConnection-helper.js'></script> |
| <script src='../webrtc/third_party/sdp/sdp.js'></script> |
| <script> |
| |
| const generateKeyFrame = (port, opts) => postMethod(port, 'generateKeyFrame', opts); |
| const generateKeyFrameDoesNotThrow = (port, opts) => postMethod(port, 'generateKeyFrameDoesNotThrow', opts); |
| const waitForFrame = port => postMethod(port, 'waitForFrame'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {audio: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| // No rids |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'InvalidStateError', `Message: ${message.message}`); |
| |
| message = await waitForFrame(receiver.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| // No rids |
| message = await generateKeyFrame(receiver.transform.port); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'InvalidStateError', `Message: ${message.message}`); |
| }, 'generateKeyFrame() throws for audio'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| // No rids |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| // value should be a timestamp |
| assert_equals(typeof message.value, 'number'); |
| assert_greater_than(message.value, 0); |
| |
| // No rids |
| message = await generateKeyFrame(receiver.transform.port); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'InvalidStateError', `Message: ${message.message}`); |
| |
| video1.srcObject = new MediaStream([receiver.track]); |
| await video1.play(); |
| }, 'generateKeyFrame(null) resolves for video sender, and throws for video receiver'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| // Invalid rid, empty string |
| message = await generateKeyFrame(sender.transform.port, {rid: ''}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| |
| // Invalid rid, bad ASCII characters |
| message = await generateKeyFrame(sender.transform.port, {rid: '!?'}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| |
| // Invalid rid, bad ASCII characters (according to RFC 8852, but not RFC 8851) |
| message = await generateKeyFrame(sender.transform.port, {rid: 'foo-bar'}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| |
| // Invalid rid, bad ASCII characters (according to RFC 8852, but not RFC 8851) |
| message = await generateKeyFrame(sender.transform.port, {rid: 'foo_bar'}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| |
| // Invalid rid, bad non-ASCII characters |
| message = await generateKeyFrame(sender.transform.port, {rid: '(╯°□°)╯︵ ┻━┻'}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| |
| // Invalid rid, too long |
| message = await generateKeyFrame(sender.transform.port, {rid: 'a'.repeat(256)}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotAllowedError', `Message: ${message.message}`); |
| }, 'generateKeyFrame throws NotAllowedError for invalid rid'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port, {rid: 'foo'}); |
| assert_equals(message.result, 'failure'); |
| assert_equals(message.value, 'NotFoundError', `Message: ${message.message}`); |
| }, 'generateKeyFrame throws NotFoundError for unknown rid'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| |
| const senderTransform = sender.transform; |
| sender.transform = null; |
| |
| message = await generateKeyFrameDoesNotThrow(senderTransform.port); |
| assert_equals(message.result, 'success'); |
| }, 'generateKeyFrame does not throw for unset transforms'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| // value should be a timestamp |
| assert_equals(typeof message.value, 'number'); |
| assert_greater_than(message.value, 0); |
| const timestamp = message.value; |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| // value should be a timestamp |
| assert_equals(typeof message.value, 'number'); |
| assert_greater_than(message.value, timestamp); |
| }, 'generateKeyFrame timestamp should advance'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| const count = message.count; |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| assert_greater_than(message.count, count); |
| }, 'await generateKeyFrame, await generateKeyFrame should see an increase in count of keyframes'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver, senderPc, receiverPc} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| |
| senderPc.getTransceivers()[0].direction = 'inactive'; |
| await senderPc.setLocalDescription(); |
| await receiverPc.setRemoteDescription(senderPc.localDescription); |
| await receiverPc.setLocalDescription(); |
| await senderPc.setRemoteDescription(receiverPc.localDescription); |
| |
| message = await generateKeyFrameDoesNotThrow(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| |
| senderPc.getTransceivers()[0].direction = 'sendonly'; |
| await senderPc.setLocalDescription(); |
| await receiverPc.setRemoteDescription(senderPc.localDescription); |
| await receiverPc.setLocalDescription(); |
| await senderPc.setRemoteDescription(receiverPc.localDescription); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| }, 'generateKeyFrame does not reject when the sender is negotiated inactive, and resumes succeeding when negotiated back to active'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver, senderPc, receiverPc} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| |
| senderPc.getTransceivers()[0].stop(); |
| |
| message = await generateKeyFrameDoesNotThrow(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| }, 'generateKeyFrame does not reject when the sender is stopped, even without negotiation'); |
| |
| promise_test(async (test) => { |
| const {sender, receiver, senderPc, receiverPc} = await createConnectionWithTransform(test, 'script-transform-generateKeyFrame.js', {video: true}); |
| let message = await waitForFrame(sender.transform.port); |
| assert_equals(message, 'got frame'); |
| |
| message = await generateKeyFrame(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| |
| await senderPc.getTransceivers()[0].sender.replaceTrack(null); |
| |
| message = await generateKeyFrameDoesNotThrow(sender.transform.port); |
| assert_equals(message.result, 'success'); |
| }, 'generateKeyFrame does not reject with a null track'); |
| |
| // TODO: It would be nice to be able to test that pending generateKeyFrame |
| // promises are _rejected_ when the transform is unset, or the sender stops |
| // sending. However, getting the timing on this right is going to be very hard. |
| // While we could stop the processing of frames before calling |
| // generateKeyFrame, this would not necessarily help, because generateKeyFrame |
| // promises are resolved _before_ enqueueing the frame into |readable|, and |
| // right now the spec does not have a high water mark/backpressure on |
| // |readable|, so pausing would not necessarily prevent the enqueue. |
| </script> |
| </body> |
| </html> |
| |