Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture google-chrome google-chrome

Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture


I had to experiment with Chrome playing sounds. It turned out that even after a user gesture (such as click) it waits for 1000ms and if no sound was played it throws the exception above. In my case the problem was coming from asynchronous track URL loading.

But it also turned out that after the first track is played chrome doesn't care anymore for this 1000ms delay and you can call play programmatically with any timeout you want.

So the solution was to play a micro almost zero-second long muted sound from static resources after the very first time a user clicks on a track and after that load a desired track URL.

Hope it helps or someone finds other solutions.


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {  webSettings.setMediaPlaybackRequiresUserGesture(false);}


Here is how I embeded this solution into soundmanager2 :

Create a function :

function playMicroTrack(scope, angularPlayer) {if (!scope.$root.isInitialized) {    soundManager.createSound({        id: '-1',        url: '../../assets/lib/microSound.mp3'    });    soundManager.play('-1');    scope.$root.isInitialized = true;    }}

Then inside the play directive use :

ngSoundManager.directive('playAll', ['angularPlayer', '$log',function (angularPlayer, $log) {    return {        restrict: "EA",        scope: {            songs: '=playAll'        },        link: function (scope, element, attrs) {            element.bind('click', function (event) {                playMicroTrack(scope, angularPlayer);                //first clear the playlist                angularPlayer.clearPlaylist(function (data) {                    $log.debug('cleared, ok now add to playlist');                    //add songs to playlist                    for (var i = 0; i < scope.songs.length; i++) {                        angularPlayer.addTrack(scope.songs[i]);                    }                    if (attrs.play != 'false') {                        //play first song                        angularPlayer.play();                    }                });            });        }    };}]);

In my case soundManager.play contains a piece of code that sends an async call to server to fetch a track url. This was causing the issue.

Hope this helps