zmxv / react-native-sound

React Native module for playing sound clips
MIT License
2.78k stars 749 forks source link

Correctly handling iOS interruptions with this package #645

Open schumannd opened 4 years ago

schumannd commented 4 years ago

:beetle: Description

We are experiencing unexplained stopping of audio playback. Sometimes with the audio progress still progressing, sometimes with the sound just stopping.

:beetle: What have you tried?

Currently there is no mention of interruptions in the README. I only found these apple docs. But as I can't reproduce this error right now it is hard to debug.

:beetle: Please post your code:

// @flow
import { Platform } from 'react-native';
import Sound from 'react-native-sound';

Sound.setCategory('Playback', false);

class Player {
  soundFile = new Sound('');

  // Used to update parent progress.
  setParentState = (obj: Object) => {}; // eslint-disable-line no-unused-vars

  // interval ID for recurring parent update function.
  parentUpdateIntervalID = null;

  // Current Song to load and play.
  filePath = '';

  /*
  Component using this class must have states 'playing', 'ended' and 'playbackTime' and pass their setState function as setParentState.
   */
  loadAndPlay = (path: string, setParentState: Function, errorCallback: Function) => {
    // Needs to be updated every time as parent component might have changed.
    this.setParentState = setParentState;

    // Handle iOS not handling full path correctly.
    let filePath = path;
    if (Platform.OS === 'ios' && filePath.includes('/Documents/')) filePath = path.split('/Documents/')[1];

    // Already loaded, just play.
    if (filePath === this.filePath) {
      this.play(errorCallback);
      return;
    }

    this.filePath = filePath;

    // Load file.
    this.soundFile.stop(() => this.soundFile.release());
    this.soundFile = new Sound(filePath, Sound.DOCUMENT, error => {
      if (error) {
        // Failed to load sound.
        errorCallback();
        return;
      }

      // Play file. (ugly bugfix https://github.com/zmxv/react-native-sound/issues/421)
      this.play(errorCallback);
      // this.enableLockscreenControls();
    });
  };

  getDuration = (): number => this.soundFile.getDuration();

  getCurrentTime = () => new Promise<number>(resolve => this.soundFile.getCurrentTime(resolve));

  setCurrentTime = (seconds: number) => {
    this.setParentState({ playbackTime: seconds });
    this.soundFile.setCurrentTime(seconds);
  };

  stopUpdatingPlaytime = () => {
    if (this.parentUpdateIntervalID) clearInterval(this.parentUpdateIntervalID);

  };

  play = async (errorCallback: Function) => {
    // Clear old interval for good measure and reinstate.
    this.stopUpdatingPlaytime();
    const playTime = await this.getCurrentTime();
    if (!playTime) this.setParentState({ playbackTime: 0.1 });
    this.parentUpdateIntervalID = setInterval(this.updateParentPlaybackTime, 2000);
    this.setParentState({ playing: true, length: this.getDuration() });
    this.soundFile.play(success => {
      if (success) {
        this.ended();
      } else {
        // Playback failed due to audio decoding errors.
        this.soundFile.reset();
        this.stop();
        errorCallback();
      }
    });
  };

  stop = () => {
    if (this.soundFile != null) {
      this.stopUpdatingPlaytime();
      this.soundFile.stop();
      this.setParentState({ playing: false });
    }
  };

  pause = () => {
    if (this.soundFile != null) {
      this.stopUpdatingPlaytime();
      this.soundFile.pause();
      this.setParentState({ playing: false });
    }
  };

  ended = () => {
    this.stopUpdatingPlaytime();
    this.setParentState({ playing: false, ended: true });
  };

  // This function is called in an interval of X ms while playing a sound.
  updateParentPlaybackTime = async () => {
    const seconds = await this.getCurrentTime();
    this.setParentState({ playbackTime: seconds });
  };

}

export default new Player();

Is your issue with...

Are you using...

Which versions are you using?

Does the problem occur on...

If your problem is happening on a device, which device?