ShadowOfCasper
@ShadowOfCasper
Middle User Interface Web Developer

Как побороть задержку воспроизведения audio на iOS?

Дано:
Кастомный аудиоплеер в виде vue-компонента с листалкой записей, кнопкой play / pause, перемоткой.

Проблема:
Встречается только на iOS устройствах, в chrome/safari + MacOS safari. Между переключением и тогглингом происходит какой-то длительный интервал времени, которого нет ни на android устройствах, ни на десктопах windows/linux. MacOS Safari вообще не производит музыку.
Разметка контролсов компонента:
<div class='audio-gallery__main-panel'>
			<div class='audio-gallery__control-btns'>
				<div class="audio-gallery__icon audio-gallery__icon--prev"
					:class='{"audio-gallery__icon--disabled": isSingle}'
					@click='moveSource("prev")'>
					<svg><use :xlink:href='"/images/sprite.svg#next" | imgPath'></use></svg>
				</div>
				<div class="audio-gallery__play" @click='togglePlayState($event)'
					:class='{"audio-gallery__play--stopped": !states.play}'>
					<svg v-if='!states.play'>
						<use :xlink:href='"/images/sprite.svg#play" | imgPath'></use>
					</svg>
					<svg v-else>
						<use :xlink:href='"/images/sprite.svg#pause" | imgPath'></use>
					</svg>
				</div>
				<div class="audio-gallery__icon audio-gallery__icon--next"
					:class='{"audio-gallery__icon--disabled": isSingle}'
					@click='moveSource("next")'>
					<svg><use :xlink:href='"/images/sprite.svg#next" | imgPath'></use></svg>
				</div>
			</div>
		</div>

Методы включения и отключения:
export default Vue.component( 'v-audio', {
		mixins: [playerMixin],
		data() {
			return {
				isAudio: true,
				soundAxis: 'x',
				metaArray: [],
				loading: false,
			}
		},
		watch: {
			'valuesArray'() {
				if (this.isSingle) {
					return
				}
				this.metaArray = [];
				this.collectMeta();
			},
			'isSingle'(oldVal, newVal) {
				if (newVal === true && oldVal === false) {
					this.$set(this, 'metaArray', []);
				}
			}
		},
		methods: {
			collectMeta() {
				this.$nextTick( () => {

					const setMeta = (item, idx) => {
						const collector = this.$refs[`metaCollector-${idx}`][0];
						collector.load();
						const pushMeta = () => {
							let obj = {
								path: item.path,
								duration: this.convertTimeHHMMSS(collector.duration)
							};
							this.metaArray.push(obj);
							collector.removeEventListener('loadedmetadata', pushMeta);
							this.$emit('init-meta', this.metaArray);

						};
						collector.addEventListener('loadedmetadata', pushMeta)
					};
					this.valuesArray.forEach((item, idx) => {
						setMeta(item, idx);
					});

				})
			},
			setPause() {
				this.$refs.player.pause();
				this.states.isPlaying = false;
			},
			togglePlayState(event) {
				if (this.states.play === true) {
					this.states.play = false;
					this.setPause();
				} else {
					this.states.play = true;
					this.playMedia();
				}
			},
			playMedia() {
				this.loading = true;
				this.$refs.player.play().then( () => {
					this.loading = false;
					this.states.isPlaying = true;
				}).catch( err => {
					console.warn(err);
				});
			},
                        moveSource(side, customSource) {
				// console.log(customSource)
				let isPlayedBefore = false;
				if (this.isAudio && this.states.play) {
					setTimeout( () => {
						this.setPause();
					}, 0)
					isPlayedBefore = true;
				};
				if (customSource !== undefined) {
					//move to custom
					this.valuesArray.forEach((item, idx) => {
						item.active = false;
						if (item.path === customSource) {
							item.active = true;
						}
					});
				} else {
					//move to next or prev
					let activeIdx = 0;
					this.valuesArray.forEach((item, idx) => {
						if (item.active) {
							activeIdx = idx;
						};
						item.active = false;
					});
					if (side === 'next') {
						if (activeIdx === this.valuesArray.length - 1) {
							this.valuesArray[0].active = true;
						} else {
							this.valuesArray[activeIdx + 1].active = true;
						}
					} else {
						if (activeIdx === 0) {
							console.log(this.valuesArray.length - 1)
							this.valuesArray[this.valuesArray.length - 1].active = true;
						} else {
							this.valuesArray[activeIdx - 1].active = true;
						}
					}
				}
				this.$refs.player.currentTime = 0;
				this.$refs.player.load();
				if (this.isAudio && isPlayedBefore) {
					setTimeout( () => {
						this.playMedia()
					}, 0)
				}
			},
		}
	})

Не могу побороть проблему уже часа два. Инфы в гугле мало. На задержку скорости загрузки грешить не стоит. Я тестил на локалке - поднял приложение на browserSync и тестил на iPhone и ноуте в локальной сети. Задержка в промисе this.$refs.player.play()
При этом в коде не встречается ошибок, во всяком случае консоль молчит.
Сначала я вообще вешал методы playMedia и setPause на вотчер стейта. Ни одно устройство apple не желало воспроизводиться вообще. Прочёл где-то на qaru что нужно вешать методы в callback события click и тогда работать будет. Это решило проблему но появилась эта задержка.
Тимми, почему я страдаю?
  • Вопрос задан
  • 234 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы