Answer the question
In order to leave comments, you need to log in
How to overcome audio playback delay on iOS?
Given:
Custom audio player as a vue component with record list, play/pause button, rewind.
Problem:
Occurs only on iOS devices, in chrome/safari + MacOS safari. There is a long time interval between switching and toggling, which is not present on both android devices, nor on windows/linux desktops. MacOS Safari doesn't produce music at all.
Component controls markup:
<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)
}
},
}
})
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question