Не удалось выполнить "воспроизведение" в "HTMLMediaElement": API может быть инициирован только жестом пользователя
Я создаю страницу для воспроизведения музыки, где я использую SoundManager 2 для 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 для android я получаю сообщение об ошибке:
Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture.
это не происходит, если песня имеет URL-адрес с самого начала, а асинхронная загрузка не используется.
Есть ли какие-нибудь обходные пути?
Ответы
Ответ 1
Мне пришлось поэкспериментировать с игровыми звуками в Chrome. Оказалось, что даже после жестов пользователя (например, щелчка) он ждет 1000 мс, и если звук не воспроизводится, он выдает исключение выше. В моем случае проблема заключалась в асинхронной загрузке URL трека.
Но также выяснилось, что после того, как первый трек будет воспроизведен, хром больше не заботится об этой задержке в 1000 мс, и вы можете вызвать программу программно с любым тайм-аутом, который вы хотите.
Таким образом, решение заключалось в том, чтобы воспроизводить микро почти почти нулевой секундой звук без звука из статических ресурсов после того, как пользователь впервые нажимает на трек и после этого загружает желаемый URL-адрес трека.
Надеюсь, что это поможет, или кто-то найдет другие решения.
Ответ 2
Вот как я включил это решение в 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;
}
}
Затем внутри директивы воспроизведения используйте:
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-адреса трека. Это вызвало проблему.
Надеюсь, что это поможет
Ответ 3
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
webSettings.setMediaPlaybackRequiresUserGesture(false);
}
Ответ 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();
}
Играя и приостанавливая сразу все звуки, вы не услышите их воспроизведение, они будут "загружены после жесты клиента", и вы сможете впоследствии их вызвать и воспроизвести.
Надеюсь, это поможет.