zmxv / react-native-sound

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

Playing the next track in the done callback of the play() function doesn't work #827

Open ArshanKhanifar opened 1 year ago

ArshanKhanifar commented 1 year ago

:beetle: Description I have an app where I have a series of tracks, they're specified by state variable index, at the callback of the play(cb) function I call setIndex(index + 1)... that in turn triggers a useEffect hook which loads the next sound and calls play() again.

It doesn't play the next sound, it just errors on "sound playback failed". I have a button on the screen that calls play() as well, and that does work, even after the error.

I tried putting the call to play() function from the useEffect hook in a setTimeout to avoid potential scheduling issues, but it still fails.

It seems that play function doesn't work if it's not triggered by a user-initiated event.

:beetle: What is the observed behavior? I see

Sound playback failed

in the console.

:beetle: What is the expected behavior? Next track should play.

:beetle: Please post your code:


import {Button, Text, View} from 'react-native';
import {useContext, useEffect, useState} from 'react';
import {useDownloadBookSection} from '../hooks/page_info';
import {BookContext} from './book_player';
import Sound from 'react-native-sound';

export const PlayerControls = ({
  playing,
  setPlaying,
  index,
  setIndex,
}: {
  playing: boolean;
  index: number;
  setIndex: (n: number) => void;
  setPlaying: (p: boolean) => void;
}) => {
  const [sound, setSound] = useState<Sound>(null!);
  const {bookName, pageNum} = useContext(BookContext);
  const {filePath, status, error} = useDownloadBookSection(
    bookName,
    pageNum,
    index,
  );

  useEffect(() => {
    console.log('filepath', filePath, 'status', status);
    if (status != 'completed') {
      return;
    }
    const sound = new Sound(filePath, '', error => {
      if (error) {
        console.log('Failed to load sound', error);
        return;
      }

      console.log('successfully loaded sound', sound);

      setSound(sound);

      if (playing) {
        play();
      }
    });

    return () => {
      if (sound) {
        sound.release();
      }
    };
  }, [filePath, status]);

  const noSound = () => {
    if (!sound) {
      console.warn('no sound!');
      return true;
    }
    return false;
  };

  const play = () => {
    if (noSound()) {
      return;
    }
    if (!playing) {
      setPlaying(true);
    }
    sound.play(success => {
      if (success) {
        console.log('Sound played successfully');
        setIndex(index + 1);
      } else {
        console.log('Sound playback failed');
      }
    });
  };

  const pause = () => {
    if (noSound()) {
      return;
    }
    setPlaying(false);
    sound.pause();
  };

  return (
    <View>
      <Text>
        status: {status}: {error}
      </Text>
      <Button
        title={playing ? 'Pause' : 'Play'}
        onPress={() => (playing ? pause() : play())}
      />
    </View>
  );
};

:bulb: Does the problem have a test case?

No

:bulb: Possible solution No

:bulb: Is there a workaround? No

:bulb: If the bug is confirmed, would you be willing to create a pull request? Yes

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?

ArshanKhanifar commented 1 year ago

ah I noticed #825 's similar to this.