wake-up-neo.net

Ausführung von 'play' für 'HTMLMediaElement' fehlgeschlagen: API kann nur durch eine Benutzergeste initiiert werden

Ich mache eine Musikwiedergabeseite, auf der ich SoundManager 2 für AngularJs verwende. Ich benutze eine Remote-API, um eine Song-URL abzuspielen. Ich habe einen Clickman-Event-Handler mit einem Soundmanager2 erweitert: 

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

Wo ich einen Teil hinzugefügt habe, der scope.loadFunction(song,callback) aufruft, und nachdem diese Funktion eine Song-URL geladen hat, ruft sie einen Rückruf auf, um das Steuerelement an angle-soundmanager2 zurückzugeben.

Das Problem ist, dass ich auf Chrome für Android eine Fehlermeldung bekomme:

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

dies geschieht nicht, wenn ein Song von Anfang an eine URL hat und das asynchrone Laden nicht verwendet wird.

Gibt es Abhilfemaßnahmen dafür?

23
andreybavt

Ich musste mit Chrome experimentieren und Sounds abspielen. Es stellte sich heraus, dass selbst nach einer Benutzergeste (z. B. Klicken) 1000 ms gewartet wird. Wenn kein Ton gespielt wurde, wird die obige Ausnahme ausgelöst. In meinem Fall war das Problem das Laden asynchroner Track-URLs.

Es stellte sich jedoch auch heraus, dass sich Chrom nach dem ersten Titel nicht mehr für diese Verzögerung von 1000 ms interessiert, und Sie können das Programm mit jedem beliebigen Timeout programmieren. 

Die Lösung bestand also darin, einen stummgeschalteten, fast null Sekunden langen Ton aus statischen Quellen abzuspielen, nachdem ein Benutzer das erste Mal auf eine Spur geklickt hat und danach eine gewünschte Spur-URL geladen hat.

Hoffe es hilft oder jemand findet andere Lösungen.

22
andreybavt

So habe ich diese Lösung in Soundmanager2 eingebettet:

Erstellen Sie eine Funktion:

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

Dann innerhalb der Spielanweisung verwenden: 

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 meinem Fall enthält soundManager.play einen Code, der einen asynchronen Aufruf an den Server sendet, um eine Track-URL abzurufen. Dies verursachte das Problem.

Hoffe das hilft

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

Ähnlich der Lösung von Andreybavt. So habe ich das Problem gelöst ... Ich habe eine Funktion geschrieben, die alle Sounds, die ich verwenden möchte, abspielen/pausieren lässt. Diese Funktion wird onClick aufgerufen. Dieser Klick ist sehr wichtig. Es wird die Geste des Benutzers erforderlich sein.

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

Wenn Sie sofort alle Sounds abspielen und anhalten, die Sie nicht hören, werden sie "nach einer Client-Geste geladen", und Sie können sie anschließend programmgesteuert aufrufen/abspielen .. _. Hoffe, das hilft.

1
Charles R.