Clone encoded WebRTC audio frame when deserializing RTCEncodedAudioFrame
This fixes the issue that structuredClone() returns an
RTCEncodedAudioFrame using the same underlying frame as the original.
Corresponding Video change: crrev.com/c/4584209
Bug: 1450844, 1456292
Change-Id: I9812ea3652b6ef4ae5f0f6d5a8d11abe456de1a7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4626956
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Auto-Submit: Tony Herre <toprice@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1159935}
diff --git a/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html b/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html
index d4b6b72..ad5af10 100644
--- a/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html
+++ b/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html
@@ -12,7 +12,7 @@
</head>
<body>
<script>
-async function testAudioFlow(t, negotiationFunction) {
+async function testAudioFlow(t, negotiationFunction, perFrameCallback = () => {}) {
const caller = new RTCPeerConnection({encodedInsertableStreams:true});
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection({encodedInsertableStreams:true});
@@ -70,50 +70,56 @@
// Pass frames as they come from the encoder.
for (let i = 0; i < numFramesPassthrough; i++) {
- const result = await senderReader.read()
+ const result = await senderReader.read();
+ const frame = result.value;
frameInfos.push({
- data: result.value.data,
- timestamp: result.value.timestamp,
- type: result.value.type,
- metadata: result.value.getMetadata(),
+ data: frame.data,
+ timestamp: frame.timestamp,
+ type: frame.type,
+ metadata: frame.getMetadata(),
getMetadata() { return this.metadata; }
});
- senderWriter.write(result.value);
+ perFrameCallback(frame);
+ senderWriter.write(frame);
}
// Replace frame data with arbitrary buffers.
for (let i = 0; i < numFramesReplaceData; i++) {
const result = await senderReader.read()
+ const frame = result.value;
const buffer = new ArrayBuffer(100);
const int8View = new Int8Array(buffer);
int8View.fill(i);
- result.value.data = buffer;
+ frame.data = buffer;
frameInfos.push({
- data: result.value.data,
- timestamp: result.value.timestamp,
- type: result.value.type,
- metadata: result.value.getMetadata(),
+ data: frame.data,
+ timestamp: frame.timestamp,
+ type: frame.type,
+ metadata: frame.getMetadata(),
getMetadata() { return this.metadata; }
});
- senderWriter.write(result.value);
+ perFrameCallback(frame);
+ senderWriter.write(frame);
}
// Modify frame data.
for (let i = 0; i < numFramesReplaceData; i++) {
const result = await senderReader.read()
- const int8View = new Int8Array(result.value.data);
+ const frame = result.value;
+ const int8View = new Int8Array(frame.data);
int8View.fill(i);
frameInfos.push({
- data: result.value.data,
- timestamp: result.value.timestamp,
- type: result.value.type,
- metadata: result.value.getMetadata(),
+ data: frame.data,
+ timestamp: frame.timestamp,
+ type: frame.type,
+ metadata: frame.getMetadata(),
getMetadata() { return this.metadata; }
});
- senderWriter.write(result.value);
+ perFrameCallback(frame);
+ senderWriter.write(frame);
}
return ontrackPromise;
@@ -207,6 +213,26 @@
assert_throws_dom("InvalidStateError", () => sender.createEncodedStreams());
}, 'Creating streams twice throws');
+promise_test(async t => {
+ let clonedFrames = [];
+ function verifyFramesSerializeAndDeserialize(frame) {
+ // Clone encoded frames using structedClone (ie serialize + deserialize) and
+ // keep a reference.
+ const clone = structuredClone(frame);
+ clonedFrames.push(clone);
+ };
+
+ await testAudioFlow(
+ t, exchangeOfferAnswer, verifyFramesSerializeAndDeserialize);
+
+ // Ensure all of our cloned frames are still alive and well, despite the
+ // originals having been sent through the PeerConnection.
+ clonedFrames.forEach((clonedFrame) => {
+ assert_not_equals(clonedFrame.data.size, 0);
+ assert_not_equals(clonedFrame.timestamp, 0);
+ });
+}, 'Encoded frames serialize and deserialize into a deep clone');
+
</script>
</body>
</html>