Impossible d'exécuter 'play' sur 'HTMLMediaElement': l'API ne peut être lancée que par un geste utilisateur

Je crée une page de lecture de musique, où j'utilise SoundManager 2 pour AngularJs . J'utilise une API distante pour obtenir une URL de morceau pour jouer. J'ai amélioré un gestionnaire d'événement de clic angulaire-soundmanager2:

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); } }); 

Où j'ai ajouté une partie, qui appelle scope.loadFunction(song,callback) et après que cette fonction charge une URL de morceau, elle appelle un rappel pour remettre le contrôle à angular-soundmanager2.

Le problème est que sur chrome pour Android, j'ai une erreur:

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

Il ne se produit pas si une chanson a une URL dès le début et le chargement asynchrone n'est pas utilisé.

Y a-t-il des solutions de contournement?

Je devais expérimenter les sons de Chrome. Il s'est avéré que même après un geste d'utilisateur (tel que cliquer), il attend 1000ms et si aucun son n'a été joué, il lance l'exception ci-dessus. Dans mon cas, le problème provenait du chargement asynchrone d'URL de piste.

Mais il s'est également avéré qu'après la première piste, chrome ne se soucie plus de ce délai de 1000ms et vous pouvez appeler une programmation programmée avec n'importe quel délai d'attente souhaité.

Donc, la solution était de jouer un son micro silencieux de près de zéro seconde à partir de ressources statiques après la première fois qu'un utilisateur clique sur une piste et après avoir chargé une URL de piste souhaitée.

J'espère qu'il aide ou quelqu'un trouve d'autres solutions.

Voici comment j'ai intégré cette solution dans soundmanager2:

Créer une fonction:

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

Ensuite, à l'intérieur de la directive play, utilisez:

 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(); } }); }); } }; } ]); 

Dans mon cas, soundManager.play contient un code qui envoie un appel asynchimique au serveur pour récupérer une URL de piste. Cela causait le problème.

J'espère que cela t'aides

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

Semblable à la solution d'andreybavt. Voici comment j'ai résolu le problème. J'ai écrit une fonction qui charge la lecture / pause de tous les sons que je veux utiliser. Cette fonction est appeléeCliquez. Ce clic est très important. Ce sera le geste de l'utilisateur requis.

 $("#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(); } 

En jouant et en arrêtant immédiatement tous les sons, vous ne les entendez pas jouer, ils seront "chargés après un geste de client" et vous pourrez les appeler / les lire par programme après. J'espère que cela t'aides.