Skip to content

Commit

Permalink
userStartAudio method starts on user gesture (#322)
Browse files Browse the repository at this point in the history
A different approach to starting the audio context on a user gesture that works with Chrome's new autoplay policy and gives the user control over whether/how to handle the success callback / Promise
  • Loading branch information
therewasaguy authored Jan 10, 2019
1 parent 02790c9 commit 16407a3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 28 deletions.
15 changes: 15 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ module.exports = function(grunt) {
}
}
});
} else if (path.indexOf('node_modules/startaudiocontext') > -1) {
// return '/** StartAudioContext.js by Yotam Mann, MIT License 2017 https://github.com/tambien/StartAudioContext http://opensource.org/licenses/MIT **/\n' +
return require('amdclean').clean({
code: contents,
escodegen: {
comment: false,
format: {
indent: {
style: ' ',
adjustMultiLineComment: true
}
}
}
});
} else {
return require('amdclean').clean({
'code':contents,
Expand All @@ -63,6 +77,7 @@ module.exports = function(grunt) {
out: 'lib/p5.sound.js',
paths: {
'Tone' : 'node_modules/tone/Tone',
'StartAudioContext' : 'node_modules/startaudiocontext/StartAudioContext',
'automation-timeline': 'node_modules/web-audio-automation-timeline/build/automation-timeline-amd',
'panner' : 'src/panner',
'shims': 'src/shims',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"grunt-open": "^0.2.3"
},
"dependencies": {
"startaudiocontext": "^1.2.1",
"tone": "0.10.0"
},
"scripts": {
Expand Down
79 changes: 51 additions & 28 deletions src/audiocontext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

define(function () {
define(['StartAudioContext'], function (require, StartAudioContext) {
// Create the Audio Context
var audiocontext = new window.AudioContext();

Expand Down Expand Up @@ -42,34 +42,57 @@ define(function () {
return audiocontext;
};

// if it is iOS, we have to have a user interaction to start Web Audio
// http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
var iOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false ;
if (iOS) {
var iosStarted = false;
var startIOS = function() {
if (iosStarted) return;

// create empty buffer
var buffer = audiocontext.createBuffer(1, 1, 22050);
var source = audiocontext.createBufferSource();
source.buffer = buffer;

// connect to output (your speakers)
source.connect(audiocontext.destination);
// play the file
source.start(0);
console.log('start ios!');

if (audiocontext.state === 'running') {
iosStarted = true;
}
};
document.addEventListener('touchend', startIOS, false);
document.addEventListener('touchstart', startIOS, false);

// TO DO: fake touch event so that audio will just start
}
/**
* <p>It is a good practice to give users control over starting audio playback.
* This practice is enforced by Google Chrome's autoplay policy as of r70
* (<a href="https://goo.gl/7K7WLu">info</a>), iOS Safari, and other browsers.
* </p>
*
* <p>
* userStartAudio() starts the <a href="https://developer.mozilla.org/en-US/docs/Web/API/AudioContext"
* target="_blank" title="Audio Context @ MDN">Audio Context</a> on a user gesture. It utilizes
* the <a href="https://github.com/tambien/StartAudioContext">StartAudioContext</a> library by
* Yotam Mann (MIT Licence, 2016). Read more at https://github.com/tambien/StartAudioContext.
* </p>
*
* <p>Starting the audio context on a user gesture can be as simple as <code>userStartAudio()</code>.
* Optional parameters let you decide on a specific element that will start the audio context,
* and/or call a function once the audio context is started.</p>
* @param {Element|Array} [element(s)] This argument can be an Element,
* Selector String, NodeList, p5.Element,
* jQuery Element, or an Array of any of those.
* @param {Function} [callback] Callback to invoke when the AudioContext has started
* @return {Promise} Returns a Promise which is resolved when
* the AudioContext state is 'running'
* @method userStartAudio
* @example
* <div><code>
* function setup() {
* var myDiv = createDiv('click to start audio');
* myDiv.position(0, 0);
*
* var mySynth = new p5.MonoSynth();
*
* // This won't play until the context has started
* mySynth.play('A6');
*
* // Start the audio context on a click/touch event
* userStartAudio().then(function() {
* myDiv.remove();
* });
* }
* </code></div>
*/
p5.prototype.userStartAudio = function(elements, callback) {
var elt = elements;
if (elements instanceof p5.Element) {
elt = elements.elt;
} else if (elements instanceof Array && elements[0] instanceof p5.Element ) {
elt = elements.map(function(e) { return e.elt});
}
return StartAudioContext(audiocontext, elt, callback);
};

return audiocontext;
});

0 comments on commit 16407a3

Please sign in to comment.