无法在 'HTMLMediaElement' 上执行 'play':API 只能由用户手势启动

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

我正在做一个音乐播放页面,我用的是SoundManager 2 for AngularJs。 我正在使用遥控器 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 不再关心这 1000 毫秒的延迟,您可以通过编程方式调用播放,并设置您想要的任何超时时间。

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

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

以下是我如何将此解决方案嵌入到 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 的解决方案。这是我解决问题的方法。 我写了一个函数来加载 play/pause 我想使用的所有声音。这个函数叫做 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();
}

通过立即播放和暂停所有您不会听到的声音,它们将是 "loaded after a client gesture" 并且之后您将能够以编程方式 call/play 它们。 希望这有帮助。

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