【问题标题】:Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture无法在“HTMLMediaElement”上执行“播放”:API 只能由用户手势启动
【发布时间】:2015-12-02 04:32:40
【问题描述】:

我正在制作一个音乐播放页面,我在其中使用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 并且不使用异步加载,则不会发生这种情况。

有什么解决办法吗?

【问题讨论】:

标签: javascript android angularjs google-chrome soundmanager2


【解决方案1】:

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

但事实证明,在播放第一首曲目后,chrome 不再关心这 1000 毫秒的延迟,您可以使用任何所需的超时以编程方式调用 play。

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

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

【讨论】:

    【解决方案2】:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      webSettings.setMediaPlaybackRequiresUserGesture(false);
    }
    

    【讨论】:

      【解决方案3】:

      这是我将此解决方案嵌入到 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。这是导致问题的原因。

      希望对你有帮助

      【讨论】:

        【解决方案4】:

        类似于 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();
        }
        

        通过立即播放和暂停您不会听到它们播放的所有声音,它们将“在客户端手势后加载”,之后您将能够以编程方式调用/播放它们。 希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2017-10-05
          • 2015-12-07
          • 1970-01-01
          • 1970-01-01
          • 2017-09-13
          • 2016-12-12
          • 1970-01-01
          • 2021-07-13
          • 2020-04-23
          相关资源
          最近更新 更多