Blockly: The play() request was interrupted by a call to pause()

Created on 27 Mar 2016  ·  22Comments  ·  Source: google/blockly

Hi,

Sometimes, I've got this error when I load the page :

undefined:1 Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

It's happens randomly and when the message is displayed in console : I can't edit dropdown list and text area.

Here is my call code and it happens just after :

        console.log('INJECT BLOCKLY')
        @blockly = Blockly.inject('blocklyDiv', {
            toolbox: @opts.toolbox
            zoom:
                controls: true,
                wheel: false,
                startScale: 0.7,
                maxScale: 3,
                minScale: 0.3,
                scaleSpeed: 1.2
            grid:
                spacing: 25
                length: 3
                colour: '#ddd'
                snap: true
        })

I've tried to delay inject with a setTimeout, but it doesn't change anything.

For information, I use "page.js" for this UI.

Thanks by advance if you've a solution.

browser help wanted low priority bug

Most helpful comment

Is valid to simply disable sound preload ? i make this change to my code and everything seems to be ok:

Blockly.WorkspaceSvg.prototype.preloadAudio_ = function() {};

All 22 comments

I have the exact same issue, thought it was somehow related to the sounds made by Blocky.

Ah, that makes sense. Try adding a return statement at the top of Blockly.WorkspaceSvg.prototype.preloadAudio_ or comment out the body of that function.

Which browser/OS does this affect? I assume there's no stack track to point back to a line in Blockly that's throwing an error?

Just have tried in private navigation mode, without any plugins and problem is the same.

My chrome version is : Version 50.0.2661.49 beta (64-bit) under OSX 10.11

@NeilFraser > Audio sounds to be the issue : no more problems when commentating internal preloadAudio_

And sounds when dropping elements are stil working.

Blockly.WorkspaceSvg.prototype.preloadAudio_=function(){
    console.log("Sounds : ", JSON.stringify(this.SOUNDS_)); 
    /*
    for(var a in this.SOUNDS_){
        var b=this.SOUNDS_[a];
        b.volume=.01;
        b.play();
        b.pause();
        if(goog.userAgent.IPAD||goog.userAgent.IPHONE)
            break;
    }
    */
};

This is a recent bug in Chromium. Since they appear to be working on it, I don't think we need to think about a workaround at our end. Especially since this is just console spam, with no user impact.
https://bugs.chromium.org/p/chromium/issues/detail?id=593273

The linked bug is not really related to this issue.

In the chrome bug the used code is:

    a.pause();
    a.play();

But in this case it's:

    a.play();
    a.pause();

In your case it's expected to get such error message, so this needs to be fixed in the Blockly.WorkspaceSvg.prototype.preloadAudio_ function.

Submit a pull request https://github.com/google/blockly/pull/471 to fix this issue, because is impacting error checking (with catch() { ... }) if you want to make sure that everything is loaded without any errors.

@MarkusBordihn : fix local sources, it seems to solve issues :)

Note that #471 breaks sounds on iOS.

Is valid to simply disable sound preload ? i make this change to my code and everything seems to be ok:

Blockly.WorkspaceSvg.prototype.preloadAudio_ = function() {};

Disabling preload works, but sounds awful when that first click is offset by up to a second.
I'm still monitoring the open bug on Chrome, https://bugs.chromium.org/p/chromium/issues/detail?id=593273

thanks!

For info, I've just published an article about this exact issue at https://developers.google.com/web/updates/2017/06/play-request-was-interrupted that tells you exactly what is happening and how to fix it.

Will play() always return undefined in older browsers that might not return a promise?

I think this have been fixed. I'm using the last version from the repo and it didn't happened

I'm still seeing this on develop.

@beaufortfrancois the solution you suggest doesn't work cross-platform.

I'm guessing we can test for the Promise result from .play(), and toggle between calling .pause() (when no return value) and @beaufortfrancois's promise based solution.

I'm no longer seeing these error messages on the published demos (master release) in Chrome 67 Mac.

In fact, if I attempt to implement @beaufortfrancois's suggestions, I get new error messages: "workspace_audio.js:120 Error loading sound "delete" DOMException: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD"

Is there any background on why preload="auto" is not a sufficient solution to preloading these files?

Is there any background on why preload="auto" is not a sufficient solution to preloading these files?

The definitive story was in a long email I send @rachel-fenichel a couple of years ago. Unless she retained it, it's gone now. The short version is I tried everything, and the existing scheme is the only one that actually worked cross-platform five years ago.

Of particular note is iOS which only plays (played?) one sound. Loading a second sound corrupted the first, if I recall correctly. Since the 'click' is by far the most important sound, I made sure that it and only it was loaded.

The other issue is that the timing of the 'click' sound is critical. If it plays a quarter second late the first time, it sounds awful. If I recall, the preloading scheme provided by browsers was rarely honoured, thus requiring a more forceful preload.

If anyone wants to dive down the rabbit hole again, feel free. I have a recollection that someone tried making changes a couple of years ago, broke things, and it all had to be rolled back.

Since I know I'll get complaints about console spam in our implementation, I took a stab at finding a solution. Surprisingly Promise.resolve(b.play()).then(() => {b.pause();}); will also fail as if Chrome resolves the promise for play even when it still hasn't played yet and calling b.pause() will throw the error anyway.

While poking around this, I also noticed that even with the volume set to 0.01, I could still hear the 'preload' click whenever I made a change that didn't pause the sound which was more annoying than the console spam.

Eventually, I came up with this monkey patch:

Blockly.WorkspaceAudio.prototype.preload = function() {
  for (var a in this.SOUNDS_) {
      var b = this.SOUNDS_[a];
      b.load();
      if (goog.userAgent.IPAD || goog.userAgent.IPHONE)
          break
  }
}

This works in the following browsers:
Google Chrome Version 67.0.3396.99 (Official Build) (64-bit)
Internet Explorer 11.0.9600.19080
Firefox 61.0.2 (64-bit)

Using load() to silently load the audio seems like it'd be an obvious first choice solution for this, so perhaps I'm missing something? I don't have the means at the moment to test on mobile platforms, nor do I have to support them at the moment.

Does .load() actually preload the sound as advertised? In other words,
with a cleared cache when running on a remote server (not localhost or the
file system) does the first real connection click happen exactly when the
block is dropped? As of a few years ago that was not the case.

Sent (awkwardly) from an Android device.

>

It seems to, at least in the 3 browsers I tried. I also checked the network tab in Chrome and found it made the request for the file during this method and not later, like during the first click from moving a block.

I believe this was fixed by https://github.com/google/blockly/pull/2614. Please let me know if anyone is still seeing this on develop.

Was this page helpful?
0 / 5 - 0 ratings