// Call this method on touch start to create and play a buffer, // then check if the audio actually played to determine if // audio has now been unlocked on iOS, Android, etc. var unlock = function(e) { // Create a pool of unlocked HTML5 Audio objects that can // be used for playing sounds without user interaction. HTML5 // Audio objects must be individually unlocked, as opposed // to the WebAudio API which only needs a single activation. // This must occur before WebAudio setup or the source.onended // event will not fire. while (self._html5AudioPool.length < self.html5PoolSize) { try { var audioNode = new Audio();
// Mark this Audio object as unlocked to ensure it can get returned // to the unlocked pool when released. audioNode._unlocked = true;
// Add the audio node to the pool. self._releaseHtml5Audio(audioNode); } catch (e) { self.noAudio = true; break; } }
// Loop through any assigned audio nodes and unlock them. for (var i=0; i<self._howls.length; i++) { if (!self._howls[i]._webAudio) { // Get all of the sounds in this Howl group. var ids = self._howls[i]._getSoundIds();
// Loop through all sounds and unlock the audio nodes. for (var j=0; j<ids.length; j++) { var sound = self._howls[i]._soundById(ids[j]);
// Fix Android can not play in suspend state. self._autoResume();
// Create an empty buffer. var source = self.ctx.createBufferSource(); source.buffer = self._scratchBuffer; source.connect(self.ctx.destination);
// Play the empty buffer. if (typeof source.start === 'undefined') { source.noteOn(0); } else { source.start(0); }
// Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55. if (typeof self.ctx.resume === 'function') { self.ctx.resume(); }
// Setup a timeout to check that we are unlocked on the next event loop. source.onended = function() { source.disconnect(0);
// Update the unlocked state and prevent this check from happening again. self._audioUnlocked = true;