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

感情迁移 提交于 2019-11-27 04:25:06

问题


I'm making a music playing page, where I use SoundManager 2 for AngularJs. I'm using a remote API to get a song URL to play. I enhanced an angular-soundmanager2 click event handler :

element.bind('click', function () {
    if (angular.isFunction(scope.loadFunction)) {
        scope.loadFunction(scope.song, function () {
            $log.debug('adding song to playlist');
            addToPlaylist(scope.song.playDetails);

        })
    } else {
        $log.debug('adding song to playlist');
        addToPlaylist(scope.song);
    }
});

Where I added a part, that calls scope.loadFunction(song,callback) and after this function loads a song URL it calls a callback to give the control back to angular-soundmanager2.

The problem is that on chrome for android I get an error :

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

it doesn't happen if a song has a URL from the beginning and async loading isn't used.

Are there any workarounds for it?


回答1:


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.




回答2:


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



回答3:


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




回答4:


Similar to andreybavt's solution. Here is how I have solved the issue. I wrote a function that loads play/pause all sounds I want to use. This function is called onClick. This click is very important. It will be the User's gesture required.

$("#myBtn").on("click", function(){
 setSounds();
});

function setSounds() {

  //Play and pause all sounds you want to use
  var audio1 = $("#mus_1")[0];
  var audio2 = $("#mus_2")[0];

  audio1.play();
  audio1.pause();

  audio2.play();
  audio2.pause();
}

By playing and pausing immediately all sounds you will not hear them play, they will be "loaded after a client gesture" and you will be able to call/play them programmatically afterwards. Hope this helps.



来源:https://stackoverflow.com/questions/32424775/failed-to-execute-play-on-htmlmediaelement-api-can-only-be-initiated-by-a-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!