执行'play'on 'HTMLMediaElement': API只能由用户手势启动

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

本文关键字:用户 启动 on play HTMLMediaElement 执行 API      更新时间:2023-09-26

我正在制作一个音乐播放页面,在这里我使用AngularJs的SoundManager 2。我使用远程API来获取要播放的歌曲URL。我增强了一个angular-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);
    }
});

我添加了一个部分,调用scope.loadFunction(song,callback),在此函数加载歌曲URL后,它调用回调将控制权交还给angular-soundmanager2。

问题是,在chrome for android我得到一个错误:

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

如果歌曲从一开始就有URL并且没有使用异步加载,则不会发生这种情况。

有什么解决方法吗?

我不得不尝试用Chrome播放声音。事实证明,即使在用户手势(如点击)之后,它等待1000毫秒,如果没有播放声音,它就会抛出上述异常。在我的情况下,问题来自于异步轨道URL加载。

但事实证明,在第一个轨道播放后,chrome不再关心这1000ms延迟,你可以用任何超时你想要的编程方式调用播放。

所以解决方案是在用户第一次点击曲目后,从静态资源中播放一段几乎零秒长的静音声音,然后加载所需的曲目URL。

希望能有所帮助,或者有人找到其他解决方案。

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

我是这样将这个解决方案嵌入到soundmanager2中的:

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

在play指令中使用:

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

在我的例子中soundManager。Play包含一段代码,该代码向服务器发送异步调用以获取曲目url。

希望能有所帮助

类似于andreybavt的解决方案。我是这样解决这个问题的。我写了一个函数,加载播放/暂停所有我想使用的声音。这个函数叫做onClick。这个点击非常重要。这将是用户需要的手势。

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

通过播放和暂停立即所有的声音,你将不会听到他们播放,他们将"加载后的客户端手势",你将能够调用/播放他们之后编程。