React - refs - audio playback - Unhandled Rejection (NotSupportedError) on iOS
Asked Answered
N

3

6

I built a react app that plays/pauses the currently selected audio just fine on desktop web browser:

playPreview() {
    if (!this.state.isPlaying) {
      this.setState({ isPlaying: true });
      this.refs.audioRef.play();
    } else {
      this.setState({ isPlaying: false });
      this.refs.audioRef.pause();
    }
  }

On iOS mobile browsers (safari and chrome mobile) I get an unhandled rejection (NotSupprted Error): The operation is not supported.

I'm aware of the issue that on iOS the audio must play from a user's gesture but I'm firing off my method with an onClick:

{!props.isPlaying 
  ? (<MdPlayCircleOutline className="play-btn" onClick={() => 
    props.playPreview()} />) 
  : (<MdPauseCircleOutline className="play-btn" onClick={() => 
    props.playPreview()} />)
}

I have an hidden element in the parent app component:

<audio ref="audioRef" src={this.state.currentSongUrl} style={{ display: 'none' }} />

So I'm assuming that it doesn't work because the onClick isn't directly audio element? If that's the case I'm sure how to combine these two requirements.

1 - Dynamically changing audio source 2 - Alternate playback and pause

Thanks in advance to any insight and help!

-Todd

Novena answered 12/2, 2018 at 13:51 Comment(0)
O
5

This might be happening because you are using deprecated syntax for ref. You should try something like this:

<audio ref={(input) => {this.audioRef = input}} src={this.state.currentSongUrl} style={{ display: 'none' }} />

and

playPreview() {
  if (!this.state.isPlaying) {
    this.setState({ isPlaying: true });
    this.audioRef.play();
  } else {
    this.setState({ isPlaying: false });
    this.audioRef.pause();
  }
}

For reference, visit: Refs and the DOM

Orthman answered 12/2, 2018 at 14:3 Comment(1)
Thank you so much for the help!Novena
S
2

This works well without any problem for all browsers.

import React, { useEffect, useRef } from 'react'

const AudioPlayer = ({url}) => {
  const audioPlayer = useRef(); 
  const [playing, setPlaying] = useState(false);

  const play = () => {
    if (url) {
      setPlaying(true);
      audioPlayer.current.play();
    }
  };

  const stop = () => {
    if (url) {
      audioPlayer.current.pause();
      audioPlayer.current.currentTime = 0;
    }
  };

  const onPlaying= () => {
    if (audioPlayer.current.paused) setPlaying(false);
  }
  
  return (
    <div onClick={(!playing ? play : stop)}>
      <audio
       src={url}
       ref={audioPlayer}         
       onTimeUpdate={onPlaying}
      >
       Your browser does not support the
       <code>audio</code> element.
      </audio>
    </div>
  )
}

export default AudioPlayer
Sleigh answered 23/6, 2022 at 14:20 Comment(0)
S
0

i use

import React from 'react'
import ReactPlayer from "react-audio-player";

let ref = null;
const stats = {play:false};

const Player = props => {
return (
    <div key={`props.id`}>
        <ReactPlayer
            src={`props.src`}
            ref={(el)=> {ref = el} }
            controls
        />
        <div onClick={()=>start()}>
            x
        </div>
    </div>
)
}
function start() {
    stats.play = !stats.play;
    console.log(stats, ref)

    if(stats.play){
        ref.audioEl.current.play()
    }else{
        ref.audioEl.current.pause()
    }
}

ReactDOM.render( <Player src="https://www.w3schools.com/html/horse.mp3" id="p1" /> , document.getElementById('root') );
Spineless answered 17/6, 2020 at 23:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.