-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The stream is not in a state that permits enqueue; new Response(readable).blob().text() resolve to [object ReadableStream] not underlying source #95
Comments
More details:
is printed to |
The problem is that recorder.ondataavailable = async (e) => {
if (e.data.size > 0) {
try {
controller.enqueue(new Uint8Array(await e.data.arrayBuffer()));
} catch (err) {
console.warn(`Response.arrayBuffer(): ${err.message}`);
reject(err);
}
} else {
controller.close();
await ac.close();
}
};
You can fix this by storing a promise between each call to However, there's a much better solution, namely to use more streams! 😁 Instead of new Promise(async (resolve, reject) => {
let controller;
const input = new ReadableStream(
{
start(_) {
return (controller = _);
},
},
{ highWaterMark: 1 }
);
const output = input.pipeThrough(new TransformStream({
async transform(blob, c) {
try {
c.enqueue(new Uint8Array(await blob.arrayBuffer()));
} catch (err) {
console.warn(`Response.arrayBuffer(): ${err.message}`);
reject(err);
}
}
}));
const ac = new AudioContext();
if (ac.state === 'suspended') {
await ac.resume();
}
const msd = new MediaStreamAudioDestinationNode(ac);
const osc = new OscillatorNode(ac);
osc.connect(msd);
osc.onended = () => {
recorder.requestData();
recorder.stop();
};
const recorder = new MediaRecorder(msd.stream, {
audioBitrateMode: 'constant',
});
recorder.onstop = async (e) => {
// console.log(e.type);
const buffer = await new Response(output).arrayBuffer();
resolve(buffer);
};
recorder.ondataavailable = async (e) => {
// console.log(e.type, e.data.size);
if (e.data.size > 0) {
controller.enqueue(e.data);
} else {
controller.close();
await ac.close();
}
};
osc.start(ac.currentTime);
recorder.start(1);
osc.stop(ac.currentTime + 1.15);
}) (I suggest you close the Chromium bug, since this is not a problem with the Chromium's streams implementation but rather with your code. Both Chromium and this polyfill behave as expected.) |
Ah, that's an unfortunate limitation of (the current version of) the polyfill. I'm planning to make the polyfill play better with native streams for version 4.0, but it's never going to be perfect. And even then, if the browser doesn't support native streams at all, then You can work around this by concatenating the // Collect all chunks
let chunks = [];
for await (const chunk of output) {
chunks.push(chunk);
}
// Concatenate into single Uint8Array
const size = chunks.reduce((acc, chunk) => acc + chunk.byteLength, 0);
const concatenated = new Uint8Array(size);
let offset = 0;
for (const chunk of chunks) {
concatenated.set(chunk, offset);
offset += chunk.byteLength;
}
resolve(concatenated.buffer); Alternatively, you can wait for |
Where does that occur? No data is enqueued when I am testing your suggestion now. I will post my findings here in a few minutes.
That should probably be included in https://github.com/MattiasBuelens/web-streams-polyfill#compliance list items? |
Yes. I was previously just pushing
My goal with the current version is to use Streams API without stroring the values in an object. |
Your suggestion achieves the expected result. Thank you for the illumination. I still do not see where I call I posted this
at the Chromium bug. I have no way to close the bug that I am aware of. |
Not that one, the one with The key insight is to realize that the event loop does not await the result of your
It's still technically true though: the polyfill faithfully implements the entire Streams API. What it doesn't do is implement all other web APIs that integrate with the Streams API, such as I do see this sort of question coming up more frequently, so I'll try to explain this better in the README.
I mean, that's probably even easier? You can pass other |
How is that possible? The handler is Reason for making
I have not performed exhaustive analysis of the comparive expense of Individual chunks are important. Developers are interested in partial audio decoding, and encoding various codecs, e.g., WebAudio/web-audio-api#337 (comment). I am testing |
Thank you, again for your analysis and solution. I will re-read the code until I gather exactly what is occuring, though I am now reminded of |
Consider this code:
Using Streams API shipped with Chromium 96.0.4651.0 (Developer Build) (64-bit)
Revision aabda36a688c0883019e7762faa00db6342a7e37-refs/heads/main@{#924134} this error is thrown
This polyfill, included as
at https://plnkr.co/edit/XwtpbXt4aqTQTIhb?preview throws
Observe that the first element of the array passed to
Promise.allSettled()
uses a basic loop in whichReadableStreamDefaultController.enqueue()
is called with aUint8Array()
as value, thenclose()
is called, then theReadableStream
is passed tonew Response()
and read to completion usingblob()
.The second element of the array follows the same pattern as the first element, except
close()
being called inMediaRecorder
dataavailable
event handler, andnew Response(readable).arrayBuffer()
called inonstop
event handler. TheTypeError
is still thrown, logged atconsole
, yet not caught intry..catch
.The third element of the array follows same pattern as first and second element, though uses
Response.blob()
, which always throws theTypeError
.I do not see anywhere in the code where
enqueue()
is called afterclose()
.Using the polyfill I did observe where the third element fulfilled, was not rejected, while the very next test with the same code
blob()
throws an error.The Streams API shipped with Chromium always throws https://bugs.chromium.org/p/chromium/issues/detail?id=1253143.
The polyfill does not resolve to the underlying data enqueued when
Response(readable).blob()
, rather appears to resolve to a stringThere should not be any error thrown. The sequence is
close()
, thennew Response(readable)
witharrayBuffer()
orblob()
chained.This behaviour of both Chromium Streams API and this polyfill makes no sense to me. (This cannot be working as intended.) Kindly illuminate.
The text was updated successfully, but these errors were encountered: