Playing many looping sources in Web Audio API starves the CPU
Reported by
marcus.g...@gmail.com,
May 9 2016
|
||||
Issue descriptionChrome Version : 49.0.2623.108 (Utvecklarversion) Ubuntu 16.04 (64 bitar) URLs (if applicable) : http://mbitsnbites.github.io/misc/web-audio-many-notes.html OS version : Linux (Ubuntu 16.04, 64-bit) Network (such as Cable/DSL/Dial up etc): Cable Audio/Video format (if applicable): n/a (Web Audio API) Special chrome flags (if applicable): Behavior in Safari (if known): Behavior in Firefox (if known): Same (see https://bugzilla.mozilla.org/show_bug.cgi?id=1271425) Video issue, Audio issue, both, neither? Audio issue (Web Audio API) Flash or HTML5? HTML5 (Web Audio API) If the browser or renderer crashed (“Aw, Snap”), please add any crash IDs from chrome://crashes (possibly after enabling crash reporting per http://support.google.com/chrome/bin/answer.py?hl=en&answer=96817) No crash. What steps will reproduce the problem? Load http://mbitsnbites.github.io/misc/web-audio-many-notes.html ... which essentially start():s a few hundred looping AudioBufferSource nodes, each followed by a Gain node that does a short zero->one->zero envelope cycle. What is the expected result? When the Gain node reaches zero, and there are no more automation events, AND the JavaScript reference to the Gain node has been dropped, the AudioContext should drop the source + gain chain since it will never generate nor process any sound again, ever. What is the actual result? Each AudioBufferSource node consumes CPU indefinitely, starting from the point in time when it is start():ed, even when the Gain node amplitude is zero. On a fairly weak dual core 1.7 GHz AMD CPU the Firefox process maxes out at 82% CPU when 256 notes have been played. Playing even more notes starts to break up the sound (glitching). Any additional information (anything else which may help us debug the issue)? This is, in my mind, a fairly trivial and common setup, and as such deserves some optimization love. Please attach the HTML5/JavaScript code or audio/video files as well as screenshot and/or videos (if applicable) See http://mbitsnbites.github.io/misc/web-audio-many-notes.html
,
May 10 2016
Is this just an example? Of course, for this example, the obvious solution is to schedule the source node to stop at or after when the gain node has reached 0. For the example, this is a known time for each. I assume you have another example where you do not know when the gain node reaches zero so you don't know when to schedule a stop for the source node. Is that right? Having said that, I think it's generally not a good idea to expect GC to release everything for you. You don't know when GC will happen so you may still run out of resources sooner than you might expect.
,
May 11 2016
You're correct. In this example I could easily schedule a stop time for the source based on the known end-of-envelope time for the gain node. In another setup that I had, the gain node and the source node were logically decoupled (i.e. only the envelope generator knew the stop time, and only the sound source had access to the source node). I will refactor my code to solve the issue, but I still think that it would be reasonable to assume that the graph could auto GC in more situations than today, e.g. when the following conditions are met: 1. A gain node has the gain value zero. 2. No more automation events are schedule for the gain value. 3. The gain value is not connected to any other node. 4. No JS referenser is held to the gain node. ...then the gain node could safely be GC:ed, just as a source node can be automatically GC:ed under certain conditions. Den 10 maj 2016 9:52 em skrev "rtoy@chromium.org via Monorail" < monorail@chromium.org>:
,
May 11 2016
On a related note, I'd also like to point out that there is a performance problem with having many pending source nodes. If you indeed add an explicit stop to the provided example (i.e. srcNode.stop(t + attack + sustain + release) just after srcNode.start(t)), you will notice that the CPU usage actually starts high and then goes down as more and more notes are played. If I change the number of notes from 256 to 1024, I will even get glitches during the start of the demo, which eventually goes away as the CPU usage goes down. If I start 2048 notes, the audio context will only play for a fraction of a second before it automatically terminates. (Again, this is on my dual 1.7 GHz CPU).
,
May 11 2016
Re c#3: Thanks for the info. Yes, you are right; we could GC nodes sooner. For your gain node, I think item 3 isn't even required. The output is silence, so we can just disconnect to from all downstream nodes and collect it right away. Adding all of these smarts to the individual nodes will take some time and debugging, of course. Re c#4: I assume all of the source nodes are connected to a gain node that is connected to the destination. This is pretty much expected behavior. If the source is connected to the destination (directly or indirectly), the source needs to check to see it needs to play the buffer. In this particular example, the "easy" solution is not to connect the source to the gain node until you're just about ready to play it. This is one reason why we have been very reluctant to implement the "patch cable" approach in crbug.com/485728. If the patch cable approach is done, source nodes will always be processing. As for the strange high CPU usage at the start, I'll have to take a closer look to see what's causing that. I don't know off-hand what it could be.
,
May 11 2016
While I understand that having many inactive source nodes connected to the main graph will consume CPU cycles, I think that it should be possible to allow for a few 1000 inactive nodes without severely affecting the total CPU load? My use case is basically to schedule all the notes of a piece of music up front - something that seems like a reasonable use of the API, or maybe I'm overoptimistic?
,
May 11 2016
I think your requests are reasonable. Currently, inactive means not connected directly or indirectly to the destination. So for your use case, create all the nodes up front, even connect them to the gain nodes, but don't connect the gain node to the destination until you're ready to play the note. We should definitely strive to do something better than this; I'm just not sure what we can do, though. :-(
,
Jun 10 2016
,
Jun 12 2017
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. If you change it back, also remove the "Hotlist-Recharge-Cold" label. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Aug 8
Need to investigate this further as an optimization. |
||||
►
Sign in to add a comment |
||||
Comment 1 by rtoy@chromium.org
, May 9 2016