zmxv / react-native-sound

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

Stoping audio before component unmount, not working #813

Closed tdammy92 closed 1 year ago

tdammy92 commented 1 year ago

:beetle: Description Currently using this package for a chat app. before i un-mount the component. am calling the stop() method to stop the audio, but it keeps playing in the background.

To stop the audio currently playing when the user leaves the page.

:beetle: What have you tried? tried calling the stop() and even d pause(), not working.

:beetle: Please post your code:

// Please post your code

const AudioPlayer = ({audioData, isUser}: any) => {
  const {data} = audioData;
  const navigation = useNavigation();
  // console.log('audio data', JSON.stringify(data?.url, null, 2));
  const song = {
    id: data?.asset_id,
    url: data?.url, // Load media from the network
    title: data?.asset_id,
    duration: data?.duration, // Duration in seconds
  };

  const [audio, setAudio] = useState<SoundPlayer>();
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);

  const Initialize = () => {
    let newSong = new SoundPlayer(song?.url, '', error => {
      if (error) {
        console.log('error Init', error);
        return;
      }

      setDuration(newSong.getDuration());
    });
    setAudio(newSong);
  };

  function seekToTime(seconds: number) {
    if (audio) {
      audio.setCurrentTime(seconds);
      setCurrentTime(seconds);
    }
  }

  function playPause() {
    if (audio) {
      if (audio?.isPlaying()) {
        audio.pause();
      } else {
        audio.play();
      }
    }
  }

  //stop audio
  function stop() {
    if (audio) {
      audio.stop();
    }
  }

  useEffect(() => {
    const unsub = Initialize();
    return unsub;
  }, []);

  useEffect(() => {
    let audioInterval = setInterval(() => {
      audio?.getCurrentTime((seconds: number, play) => {
        setCurrentTime(seconds);
      });
    }, 100);

    return () => {
      clearInterval(audioInterval);
    };
  }, [song]);

  useEffect(() => {
    const unsubscribe = navigation.addListener('beforeRemove', () => {
      audio?.stop();
      audio?.release();

      console.log('this component is about to be removed');
    });
    return unsubscribe;
  }, [navigation]);

  return (
    <View style={styles.audioContainer}>
      <TouchableOpacity
        onPress={playPause}
        disabled={!audio?.isLoaded()}
        style={[
          styles.playPauseWrapper,
          {borderColor: isUser() ? colors.bootomHeaderBg : colors.secondaryBg},
        ]}>
        {audio?.isLoaded() ? (
          <Ionicons
            name={audio?.isPlaying() ? 'pause' : 'play'}
            color={isUser() ? colors.bootomHeaderBg : colors.secondaryBg}
            size={hp(18)}
          />
        ) : (
          <Ionicons
            name={'stop'}
            color={isUser() ? colors.bootomHeaderBg : colors.secondaryBg}
            size={hp(18)}
          />
        )}
      </TouchableOpacity>
      <View style={{position: 'relative', height: hp(35)}}>
        <Slider
          //@ts-ignore
          value={currentTime}
          minimumValue={0}
          maximumValue={duration}
          onComplete={(value: any) => {
            console.log('value from slider', value);
            seekToTime(value);
          }}
          onChange={(value: any) => {
            console.log('value from slider 2', value);
            seekToTime(value);
          }}
          thumbSize={20}
          progressTrackColor={
            isUser() ? colors.bootomHeaderBg : colors.secondaryBg
          }
          trackStyle={{
            width: 150,
            height: hp(5),
            borderRadius: hp(3),
            backgroundColor: colors.darkGray,
          }}
          thumbStyle={{
            width: 15,
            height: 15,
            borderRadius: hp(10),
            backgroundColor: isUser()
              ? colors.bootomHeaderBg
              : colors.secondaryBg,
          }}
        />

        <Text
          style={[
            styles.lenghtStart,
            {color: isUser() ? colors.bootomHeaderBg : colors.dark},
          ]}>
          {formatTimeString(currentTime)}
        </Text>
        <Text
          style={[
            styles.lenghtEnd,
            {color: isUser() ? colors.bootomHeaderBg : colors.dark},
          ]}>
          {formatTimeString(duration ?? song?.duration)}
        </Text>
      </View>
    </View>
  );
};

:bulb: Possible solution

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?

tdammy92 commented 1 year ago

Please any one who can help on this ?

mayur-shelar commented 1 year ago

@tdammy92 I am facing same issue. Did you find any solution?

tdammy92 commented 1 year ago

@mayur-shelar not yet , I might just remove the package completely. cause why would sound continue playing when user has left the screen. I want to belive there is somthing we might be missing out. but no body is even ready to help. 🤷🏽‍♂️

mayur-shelar commented 1 year ago

@tdammy92 I am able to stop the audio before the screen unmount. Simply add audio in the dependency array of useEffect were you are performing the operations which are to done before unmount. In our case it will like useEffect(() => { const unsubscribe = navigation.addListener("beforeRemove", () => { audio?.stop(); audio?.release(); }); return unsubscribe; }, [navigation, audio]); When the component mounts the state variable audio is empty. So what I found while debugging is when listener is triggered audio was undefined when audio was not passed in the dependency array.

tdammy92 commented 1 year ago

@mayur-shelar Thank you very much bro, Your a life saver.