N
N
Nikita Kit2019-03-23 00:57:27
JavaScript
Nikita Kit, 2019-03-23 00:57:27

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>

Enable and disable methods:
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)
        }
      },
    }
  })

I can not overcome the problem for two hours. Little info on google. You should not sin on the delay in download speed. I tested on local - I raised the application on browserSync and tested on the iPhone and laptop in the local network. Delay in the this.$refs.player.play() promise
At the same time, there are no errors in the code, in any case, the console is silent.
At first, I generally hung up the playMedia and setPause methods on the watcher state. No apple device wanted to play at all. I read somewhere on javascript that you need to hang methods in the click event callback and then it will work. This solved the problem, but there was this delay.
Timmy, why am I suffering?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question