5

Sandbox demo of my problem: https://codesandbox.io/s/jolly-fermat-j23w9

I'm trying to implement a feature on my React site where a user clicks an element, and the audio plays.

On desktop, this is working fine. But on iOS devices, I am encountering an "Unhandled Rejection (NotAllowedError)". This error usually is caused by autoplaying media on iOS devices. However, in this case, the user must click the element to start the audio, so this error should not be happening.

My suspicion is that because the component rerenders on state change, React doesn't know that the user had to interact with the site in order to trigger the audio.

Here is the basic code:

// audio playing function, found on this stackoverflow question:
// https://stackoverflow.com/questions/47686345/playing-sound-in-reactjs
const useAudio = url => {
  const [audio] = useState(new Audio(url));
  const [playing, setPlaying] = useState(false);

  const toggle = () => setPlaying(!playing);

  useEffect(() => {
    playing ? audio.play() : audio.pause();
  }, [playing]);

  return [playing, toggle];
};

// url of audio is passed in as prop from App.js
const PlayAudio = ({ url }) => {
  const [playing, toggle] = useAudio(url);

  return (
    <>
      <PlayButton onClick={toggle}>{playing ? "Pause" : "Play"}</PlayButton>
    </>
  );
};

Tested on an iPhone using Safari, Chrome, and Firefox browsers.

Again, a full working demonstration can be found here, and you need to check on an iOS device to see the error: https://codesandbox.io/s/jolly-fermat-j23w9

Any help is appreciated.

damon
  • 2,687
  • 8
  • 25
  • 35
  • 1
    Tested on Android Device and Chrome 77.03865.116 and it's played. – Oleg Oct 22 '19 at 04:32
  • 1
    but You can try another way with audio ref: – Oleg Oct 22 '19 at 04:34
  • Thanks @Oleg. In some brief testing, I can confirm that using refs will avoid the error in my original question. While this functionally solves my problem, I still will leave the question up both because I would still like to know exactly why this error occurs, but also because I am already using a good number of refs in my project, and the React docs suggest not to overuse them. – damon Oct 22 '19 at 16:01
  • I will also edit the question to clarify that this seems to be strictly iOS issue, not a mobile issue. Thanks for testing that. – damon Oct 22 '19 at 16:01
  • Can you try this sample in IOS: https://codesandbox.io/s/lpzr84p39z – Oleg Oct 22 '19 at 16:29
  • And also try with chrome – Oleg Oct 22 '19 at 16:32
  • I tested in Safari, Chrome, and Firefox (all ios13) and am receiving the Unhandled Rejection (NotAllowedError) for all 3 browsers. The error actually pops up as soon as the page loads, before I can press any buttons or start the audio – damon Oct 22 '19 at 16:36
  • Can you try another format like mp3? – Oleg Oct 22 '19 at 16:41
  • I can confirm that using mp3 makes no difference – damon Oct 23 '19 at 17:43

2 Answers2

1

Created example with yours code but another approach:

 <audio ref....> 

https://codesandbox.io/s/elegant-black-c0jr8

Oleg
  • 3,580
  • 1
  • 7
  • 12
  • So your example works on my iOS device. However, before you created your example, I attempted to recreate my example using `refs` as you suggested, and interestingly enough I am still getting the error I described above on my iPhone. You can see here: https://codesandbox.io/s/winter-voice-kze0f So it seems that the issue is not necessarily using `refs` vs `hooks`, but whatever way I implemented refs vs the way you did. This might explain the root of the issue in my original question, since your example works, but mine doesn't, despite them both using refs. – damon Oct 23 '19 at 17:42
  • I also tested a fork of your sandbox where the only difference was the `src` was defined in the ` – damon Oct 23 '19 at 17:53
  • Didn't understand, have you solution? – Oleg Oct 23 '19 at 17:55
  • Functionally, yes. Though Im still not sure why the error comes up, especially in my commented sandbox above. And the one drawback of your solution is that the audio restarts every time, and does not pause. Thanks for all your help Oleg. – damon Oct 23 '19 at 18:03
  • 1
    Interestingly, your updated answer makes the error pop up on my iPhone :( – damon Oct 23 '19 at 18:21
  • another try ( i have no iphone) https://codesandbox.io/s/elegant-black-c0jr8 – Oleg Oct 23 '19 at 18:34
  • Unfortunately the error still pops up when I press "Play" – damon Oct 23 '19 at 19:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201346/discussion-between-oleg-and-damon). – Oleg Oct 23 '19 at 19:35
0

This should work: setTimeout(audio.play)

Johnny Kontrolletti
  • 727
  • 1
  • 10
  • 22
  • Please don't just answer with a code snippet. Try to explain what you are contributing to the topic or how your answer differs from the others. – H3AR7B3A7 Jul 08 '22 at 18:50