React-native-sound: Problems with whoosh.reset()

Created on 14 Sep 2017  Â·  9Comments  Â·  Source: zmxv/react-native-sound

Hi,

My error is:

undefined is not a function (evaluating 'whoosh.reset()')

When i use this:

whoosh.play((success) => {
  if (success) {
    console.log('successfully finished playing');
  } else {
    console.log('playback failed due to audio decoding errors');
    // reset the player to its uninitialized state (android only)
    // this is the only option to recover after an error occured and use the player again

    whoosh.reset(); //crash line
  }
});

The library works fine for a while. I do many tests, I have lost count of how many times I have tried to reproduce audio in the same session with this library. After many times .. Maybe about 20 or so, begins to respond for the else of the play, showing log:

playback failed due to audio decoding errors.

in index.d.ts file i not found reset function

I'm testing with android.

The library Version "react-native-sound": "^0.10.3", inside package.json.

The main problem is that this way I remove whoosh.reset(); line, the library never play any audio again

Most helpful comment

Based on the demo code, I had to use the pattern on creating the instance of Sound and play the sound in onLoad callback and release it after play finish. I think it had to do with how android keep track of the resources for media file and had some limit on it.

Here are the code I use, it seems to work on both iOS and Android:

import Sound from 'react-native-sound';
import Sounds from "./Sounds";

// Enable playback in silence mode (iOS only)
Sound.setCategory('Playback', false); // true to mixWithOthers

let playingSounds = [];

class SoundPlayer {

  static stopCurrentPlayingSounds() {
    for (let sound of playingSounds) {
      sound.stop(() => {
        sound.release();
      });
    }
    playingSounds = [];
  }

  static play(soundKey, shouldStopOther = true) {

    if (shouldStopOther) {
      SoundPlayer.stopCurrentPlayingSounds();
    }

    return new Promise((resolve, reject) => {
      let data = Sounds[soundKey];
      // console.log("Playing", soundKey, data);

      let sound = new Sound(data.filename, Sound.MAIN_BUNDLE, (error) => {
        if (error) {
          console.warn('Failed to load', data, error);
          reject(new Error("Failed to load " + data.filename));
          return;
        }

        // loaded successfully
        // console.log('loaded successfully', data, 'duration: ' + sound.getDuration() + ' channels: ' + sound.getNumberOfChannels());
        playingSounds.push(sound);

        sound.play(success => {
          // Release when it's done so we're not using up resources
          sound.release();

          if (success) {
            // console.log("Done playing", soundKey, data.filename, sound._key);
            resolve(data);
            return;
          }

          // reset the player to its uninitialized state (android only)
          // this is the only option to recover after an error occured and use the player again
          sound.reset();
          // failed due to audio decoding errors
          console.warn("Failed to play", soundKey, data.filename, sound._key);
          reject(new Error("Failed to play " + data.filename));
        });
      }); // new Sound
    }); // new Promise
  }
}

export default SoundPlayer;

All 9 comments

I can confirm current version 0.10.4 missing reset, getSystemVolume and setSystemVolume methods compare to current master branch.

$ grep 'version' /tmp/test-sound/node_modules/react-native-sound/package.json
  "version": "0.10.4"

$ diff /tmp/test-sound/node_modules/react-native-sound/sound.js /tmp/react-native-sound/sound.js
10c10
<   return !/^(\/|http(s?))/.test(path);
---
>   return !/^(\/|http(s?)|asset)/.test(path);
46c46
<     onError && onError(error);
---
>     onError && onError(error, props);
76a77,83
> Sound.prototype.reset = function() {
>   if (this._loaded && IsAndroid) {
>     RNSound.reset(this._key);
>   }
>   return this;
> };
>
79a87
>     this._loaded = false;
103a112,125
>   }
>   return this;
> };
>
> Sound.prototype.getSystemVolume = function(callback) {
>   if(IsAndroid) {
>     RNSound.getSystemVolume(callback);
>   }
>   return this;
> };
>
> Sound.prototype.setSystemVolume = function(value) {
>   if (IsAndroid) {
>     RNSound.setSystemVolume(value);

I had to work around this by installing current master branch:

yarn remove react-native-sound
yarn add react-native-sound@git+https://github.com/zmxv/react-native-sound#f28be771cc728366ddb14f07bbe863fd40879cac

The reset-method has been added after 0.10.4 has been released. You can use the master branch as @ninegene suggests.

hi @gvenk

i'm using master version react-native-sound@git+https://github.com/zmxv/react-native-sound#f28be771cc728366ddb14f07bbe863fd40879cac as mentioned by @ninegene .

I can actually see that reset is already available in theindex.d.ts file. But reset still gives me crash. It looks like whoosh is undefined when this error occurs.

And you're still using this code?

````
whoosh.play((success) => {
if (success) {
console.log('successfully finished playing');
} else {
console.log('playback failed due to audio decoding errors');
// reset the player to its uninitialized state (android only)
// this is the only option to recover after an error occured and use the player again

whoosh.reset();

}
});
````

What's the exact error? And did you try to do a clean build after upgrading react-native-sound?

ok..

Removing node_modules folder, running yarn cache clean and run yarn install again. Solve crash when whoosh.reset(); is called.

But reset not fix my error. When playback failed due to audio decoding errors occurs, the only way that exists to get out of that error is restarting the app.

IOS works perfect.

_CODE:_

  playSoundTurn() {

    if (this.state.showPlayingModal) {
      this.forcePlayAudio();
    }

    playQuantity = playQuantity + 1;

    var me = this;
    let url = SERVER_URL + this.props.url;
    console.log('url ===> ', url);

    this.setState({
      showPlayingModal: true
    });

    this.stopSound((finishPause) => {
      console.log('finishPause ===> ', finishPause);
      whoosh = new Sound(url, '', (error) => {
        if (error) {
          console.log('failed to load the sound', error);
          return;
        }

        this.setState({
           showPlayingModal: false
        });

        console.log('loaded successfully');
        this.forcePlayAudio();
      });
    });
  }

  forcePlayAudio() {
    whoosh.play((success) => {
      if (success) {
        console.log('successfully finished playing');
      } else {
        console.log('playback failed due to audio decoding errors');
        this.tryPlayAudioAgain();
      }
    });
  }

  tryPlayAudioAgain() {

    if (Platform.OS === "android")
      whoosh.reset();

    if (playQuantity < 3) {
      setTimeout(() => { this.playSoundTurn(); }, 1000);
    } else {
      playQuantity = 0;
      this.errorAlert('Error', 'error playing audio');
    }
  }

  stopSound(callback) {
    if (whoosh != null) {
      whoosh.stop(() => {
          callback(true);
      });
    } else {
        callback(true);
    }
  }

The logic that I am applying:

I can play many audios and can only play 1 at a time. For this reason I always call stop before calling the play. When something goes wrong I have a logic that tries for 3 more times and if it does not work either, an error alert is displayed.

How to replicate it:

I have an audio that when trying to play it takes a lot of time, maybe 25 seconds to start (in ios starts immediately) The audio duration is 47 seconds. When I press it again the playback failed due to audio decoding errors error occurs. This way I can replicate 100% of the time

Based on the demo code, I had to use the pattern on creating the instance of Sound and play the sound in onLoad callback and release it after play finish. I think it had to do with how android keep track of the resources for media file and had some limit on it.

Here are the code I use, it seems to work on both iOS and Android:

import Sound from 'react-native-sound';
import Sounds from "./Sounds";

// Enable playback in silence mode (iOS only)
Sound.setCategory('Playback', false); // true to mixWithOthers

let playingSounds = [];

class SoundPlayer {

  static stopCurrentPlayingSounds() {
    for (let sound of playingSounds) {
      sound.stop(() => {
        sound.release();
      });
    }
    playingSounds = [];
  }

  static play(soundKey, shouldStopOther = true) {

    if (shouldStopOther) {
      SoundPlayer.stopCurrentPlayingSounds();
    }

    return new Promise((resolve, reject) => {
      let data = Sounds[soundKey];
      // console.log("Playing", soundKey, data);

      let sound = new Sound(data.filename, Sound.MAIN_BUNDLE, (error) => {
        if (error) {
          console.warn('Failed to load', data, error);
          reject(new Error("Failed to load " + data.filename));
          return;
        }

        // loaded successfully
        // console.log('loaded successfully', data, 'duration: ' + sound.getDuration() + ' channels: ' + sound.getNumberOfChannels());
        playingSounds.push(sound);

        sound.play(success => {
          // Release when it's done so we're not using up resources
          sound.release();

          if (success) {
            // console.log("Done playing", soundKey, data.filename, sound._key);
            resolve(data);
            return;
          }

          // reset the player to its uninitialized state (android only)
          // this is the only option to recover after an error occured and use the player again
          sound.reset();
          // failed due to audio decoding errors
          console.warn("Failed to play", soundKey, data.filename, sound._key);
          reject(new Error("Failed to play " + data.filename));
        });
      }); // new Sound
    }); // new Promise
  }
}

export default SoundPlayer;

hi @ninegene thanks for answer.

Today I have decided to put aside react-native-sound and move on to react-native-audio-toolkit and although I have had the same delay problem in the same audio I mentioned, this delay is not as great as the one I had before and most important of all, it works perfect for me. I have not had any error playing any audio file.

I think the problem of the delay I have is an audio file problem and not something of any of the 2 libraries, since it always happens with the same audio and the problem persists in 2 different libraries.

I know mine must be an isolated case and does not mean that this library is bad, because there are up to today 842 people who have worked great. It's a shame that not me. :(

Also getting undefined is not a function (evaluating 'e.reset()') in our Sentry logs.
meaning calling .reset() crashes.

When will the npm get the latest version of master?

Was this page helpful?
0 / 5 - 0 ratings