Skip to content
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

catch unhandled Promise in decodeAudioData #2079

Merged
merged 5 commits into from
Oct 2, 2020
Merged

Conversation

thijstriemstra
Copy link
Contributor

@thijstriemstra thijstriemstra commented Sep 30, 2020

use promise-based syntax for decodeAudioData where possible.

headless is broken since Chrome 83 for some reason.
@thijstriemstra
Copy link
Contributor Author

Interesting to see these errors on firefox: https://travis-ci.org/github/katspaugh/wavesurfer.js/builds/731591098#L1254

Firefox 81.0 (Linux x86_64) WaveSurfer/MediaElement: should set mute FAILED

Unhandled promise rejection: EncodingError: The buffer passed to decodeAudioData contains an unknown content type.

Where is this promise rejected..

@thijstriemstra
Copy link
Contributor Author

When I replace the existing decodeAudioData call in webaudio.js with:

diff --git a/src/webaudio.js b/src/webaudio.js
index 65a41b2..cb4e716 100755
--- a/src/webaudio.js
+++ b/src/webaudio.js
@@ -348,11 +348,18 @@ export default class WebAudio extends util.Observer {
                 this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100
             );
         }
+        this.offlineAc.decodeAudioData(arraybuffer).then(
+            (data) => callback(data)
+        ).catch(
+            (err) => errback(err)
+        );
+        /*
         this.offlineAc.decodeAudioData(
             arraybuffer,
             data => callback(data),
             errback
         );
+        */
     }
 
     /**

I don't see these errors anymore. According to https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/decodeAudioData the Promise based syntax of decodeAudioData is not supported in Safari (desktop and mobile). We'll have to make exception there and use the old syntax for Safari instead?

@sundayz
Copy link
Contributor

sundayz commented Sep 30, 2020

Interesting to see these errors on firefox: https://travis-ci.org/github/katspaugh/wavesurfer.js/builds/731591098#L1254

Firefox 81.0 (Linux x86_64) WaveSurfer/MediaElement: should set mute FAILED

Unhandled promise rejection: EncodingError: The buffer passed to decodeAudioData contains an unknown content type.

Where is this promise rejected..

I've seen this error in a production app too, but they don't seem to break anything... Happens during load/unload I think.

The tests seem to fail in places where wavesurfer calls methods like play() or pause() which should be promises, but the wavesurfer functions are synchronous.

@thijstriemstra
Copy link
Contributor Author

I've seen this error in a production app too, but they don't seem to break anything... Happens during load/unload I think.

That Promise exception needs to be handled though.

@thijstriemstra
Copy link
Contributor Author

We'll have to make exception there and use the old syntax for Safari instead?

How would I properly check if Promise syntax is supported (without checking for Safari user-agent)?

@coveralls
Copy link

coveralls commented Sep 30, 2020

Coverage Status

Coverage decreased (-0.09%) to 80.741% when pulling 99eeb21 on ci-chrome-disable into a33cea8 on master.

@sundayz
Copy link
Contributor

sundayz commented Sep 30, 2020

That Promise exception needs to be handled though.

What is it though? Decoding interrupted because destroy() is called?

@thijstriemstra
Copy link
Contributor Author

What is it though? Decoding interrupted because destroy() is called?

Good question.. Something like that..

@sundayz
Copy link
Contributor

sundayz commented Sep 30, 2020

We'll have to make exception there and use the old syntax for Safari instead?

How would I properly check if Promise syntax is supported (without checking for Safari user-agent)?

Use callbacks like this (first answer). you can create your own promise and resolve/reject in the callback.

https://stackoverflow.com/questions/52489787/audiocontext-decodeaudiodata-not-working-on-iphone-but-working-everywhere-e

@thijstriemstra
Copy link
Contributor Author

Use callbacks like this (first answer).

But I want to use Promise everywhere and your workaround on unsupported browsers only. How to check if a browser, e.g. Safari for example, supports it?

@sundayz
Copy link
Contributor

sundayz commented Sep 30, 2020

Callbacks version is supported everywhere so we make our own promise version:

async function decodeAudioDataAsync(ac, arrayBuffer) {
	return new Promise((resolve, reject) => {
		ac.decodeAudioData(arrayBuffer, resolve, reject);
	});
}

Usage:

try {
	const buffer = await decodeAudioDataAsync(audioContext, arrayBuffer);
	// successfully decoded
} catch (err) {
	console.error(err);
}

Change as you see fit

@thijstriemstra
Copy link
Contributor Author

Callbacks version is supported everywhere

The thing is, this Promise unhandled rejection is only caught when using the Promise based syntax. When using the old syntax the Promise is not caught and that's the whole point of this fix: catch that Promise.

@sundayz
Copy link
Contributor

sundayz commented Sep 30, 2020

I see. Check the return type of decodeAudioData? I guess it will return nothing on browsers that dont support promise syntax?

@thijstriemstra
Copy link
Contributor Author

typeof(f.decodeAudioData); returns "function" on Safari and Firefox. I obviously don't want to call the legacy callback method in order to check if there's support for Promises. Ugh.

@thijstriemstra
Copy link
Contributor Author

Fortunately(?), Safari still uses webkitAudioContext so checking for that should be enough.

@sundayz
Copy link
Contributor

sundayz commented Oct 1, 2020

typeof(f.decodeAudioData); returns "function" on Safari and Firefox. I obviously don't want to call the legacy callback method in order to check if there's support for Promises. Ugh.

It's typeof(f.decodeAudioData()), you forgot to call the function

@thijstriemstra
Copy link
Contributor Author

you forgot to call the function

Yea because I don't want to make a useless, extra call just to add a workaround for Safari.

@thijstriemstra thijstriemstra changed the title ci: disable Chrome for now catch unhandled Promise in decodeAudioData Oct 2, 2020
@thijstriemstra thijstriemstra merged commit 1a8fea7 into master Oct 2, 2020
@thijstriemstra thijstriemstra deleted the ci-chrome-disable branch October 2, 2020 12:22
marizuccara pushed a commit to marizuccara/wavesurfer.js that referenced this pull request Nov 28, 2020
* ci: disable Chrome for now

headless is broken since Chrome 83 for some reason.

* use Chrome_dev locally

* test: fix precision varying on different platforms

* use promise-based syntax for decodeAudioData and make exception for Safari
sandiz pushed a commit to sandiz/wavesurfer.js that referenced this pull request Sep 1, 2021
* ci: disable Chrome for now

headless is broken since Chrome 83 for some reason.

* use Chrome_dev locally

* test: fix precision varying on different platforms

* use promise-based syntax for decodeAudioData and make exception for Safari
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants