cookpete / react-player

A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
https://cookpete.github.io/react-player
MIT License
8.98k stars 1.12k forks source link

About autoplay in iOS platform #76

Closed KevinChien closed 7 years ago

KevinChien commented 7 years ago

Hi CookPete,

I have a problem about iOS9 with attribute 'autoplay' in html5 tag

It can work on simple sample without ReactPlayer, just use audio tag and set resource and do that steps which I run after componentDidMount. But ReactPayer cannot, because it create two audio tag in the same time. First player is SoundCloud, second is FilePlayer. I cannot select correct audio tag, because document.querySelector always only return the first target it found(not array, I don't why).

So my solution in function componentDidMount is :
.... var audio = document.querySelector("audio"); audio.remove(); //I know this is point to

I know this solution is not good, so I hope you can provide a method or prop for user(developer) to decide which player they really want to use only, not all player which can current URL resource.

Here is committed log that you did in 15 Dec 2015.

You add a map to generate each player which can play url resource. Maybe you have some consideration, I really hope you can help me to solve this problem. This library is very useful for me, so I hope it can be better than past.

Thanks!

Regards Kevin.Chien

denisflorkin commented 7 years ago

Hi, @KevinChien did you tried the document.querySelectorAll() method? It should return more than the first match. (Not that this solve the problem you address, but this might already help :) )

KevinChien commented 7 years ago

Hi @denisflorkin, document.querySelectorAll() is good for me, but I still need to do compare to confirm which player I want. I still hope @CookPete can help me to solve this issue. Thanks a lots!

cookpete commented 7 years ago

Hi @KevinChien,

You can add any attribute you like to the correct audio tag by passing an attributes object into the fileConfig prop, like this:

<ReactPlayer
  url='file.mp3'
  playing
  fileConfig={{ attributes: { autoPlay: true }}
/>

There is also refs.player exposed within ReactPlayer for the player that is currently active, so if you wanted to get the <audio> element specifically for FilePlayer, you could do something like:

componentDidMount () {
  // This assumes that `FilePlayer` is the currently active player
  const audio = this.refs.reactPlayer.refs.player
  audio.load()
  audio.play()
}
render () {
  return (
    <ReactPlayer
      ref='reactPlayer'
      url='file.mp3'
      playing
      fileConfig={{ attributes: { autoPlay: true }}
    />
  )
}

That should do the trick for now. If the load() and play() hack fixes autoplay behaviour on iOS9 then perhaps it is worth sniffing the user agent and doing this by default in ReactPlayer on iOS devices.

cookpete commented 7 years ago

I've just realised that fileConfig isn't actually passed down properly, so this solution may not work just yet. How embarrassing.. I'll push a fix shortly.

cookpete commented 7 years ago

Also note that the autoPlay attribute must use a capital P, due to React's DOM differences.

KevinChien commented 7 years ago

Hi @CookPete, I test the solution that you committed 4 days ago. It works. And something I want to let you know as below:

componentDidMount () {
  // This assumes that `FilePlayer` is the currently active player
  const audio = this.refs.reactPlayer.refs.player
  /*
    If you set autoplay = true, you won't to run load() and play() of audio or video instance.
   And you set autoplay=false then run load() and play(), the src path will be undefined just like
   src="http://localhost/undefined"
   Maybe something not ready, I have no idea about this. Just remaining the operation flow if anyone is 
   using this function. :)
  */
  audio.load() 
  audio.play()
}
render () {
  return (
    <ReactPlayer
      ref='reactPlayer'
      url='file.mp3'
      playing    //It should be playing = {true | false} right?
      fileConfig={{ attributes: { autoPlay: true }}
    />
  )
}

The solution works both on android and iOS(at least 9.3.x)

But I found the volume cannot work as other platform, if change volume in browser of iOS.(Such like safari or chrome, etc.)

All information I searched is "Volume is readonly in iOS"

See also here

BTW, anyone know the way if we hope to change the volume when we using the

At last, @CookPete thanks for you solution, it is useful for me!

Thanks.

cookpete commented 7 years ago

BTW, anyone know the way if we hope to change the volume when we using the in iOS with browser

From the Safari dev docs:

On iOS devices, the audio level is always under the user’s physical control. The volume property is not settable in JavaScript. Reading the volume property always returns 1.

Also:

playing //It should be playing = {true | false} right?

See boolean attributes. <Component test /> is the same as <Component test={true} />

KevinChien commented 7 years ago

@CookPete thanks again!

jainanshul commented 7 years ago

Solution at https://github.com/CookPete/react-player/issues/76#issuecomment-227371045 doesn't seem to be working for me. I keep getting audio.load() is not a function error. Has anyone able to get it to work with recent releases?

KevinChien commented 7 years ago

Hi @jainanshul, Maybe you can try to print instance to make sure the instance is created. I guess it is a generation process issue. Or you can post your key point code of your problem here. Hope this helpful for you. :)

//Depend on sample code that @CookPete provide
componentDidMount () {
  // This assumes that `FilePlayer` is the currently active player
  const audio = this.refs.reactPlayer.refs.player
  //Of course, if you can use develop tool of chrome to set check point, you can watch the point via code executing.
  console.log("this.refs.reactPlayer", this.refs.reactPlayer);
  console.log("this.refs.reactPlayer.refs.player", this.refs.reactPlayer.refs.player);
  audio.load()
  audio.play()
}
render () {
  return (
    <ReactPlayer
      ref='reactPlayer'
      url='file.mp3'
      playing
      fileConfig={{ attributes: { autoPlay: true }}
    />
  )
}
struggle-lulu commented 6 years ago

I keep getting refs.player is unidefind ; How to implement automatic playback audio;

//Depend on sample code that @CookPete provide
componentDidMount () {
  // This assumes that `FilePlayer` is the currently active player
  const audio = this.refs.reactPlayer.refs.player
  console.log("this.refs.reactPlayer", this.refs.reactPlayer);
//unidefined
  console.log("this.refs.reactPlayer.refs.player", this.refs.reactPlayer.refs.player);
  audio.load()
  audio.play()
}
render () {
  return (
    <ReactPlayer
      ref='reactPlayer'
      url='file.mp3'
      playing
      fileConfig={{ attributes: { autoPlay: true }}
    />
  )
}
cookpete commented 6 years ago

@struggle-lulu Since version v0.10.0 the way to access the <audio> tag would be this.refs.reactPlayer.player.player. The breaking commit is https://github.com/CookPete/react-player/commit/6c16ba0f44d0403ae3e089ca1dafed0077b095e7

See an example jsFiddle using the new ref callback function. It is a bit weird but I'm looking at making this clearer in version 1.0.

iicdii commented 6 years ago

I tried to run below link in iOS 10.3.3 safari it doesn't work. https://jsfiddle.net/99ee3atp/19/ I think iOS 10 needs user gesture to play audio element anyway..or is there any solution about this?

cookpete commented 6 years ago

I think iOS 10 needs user gesture to play audio element anyway..

This would not surprise me. This has always been an issue and iOS will continue to fix the hacks that people come up with to autoplay media on iOS devices.

struggle-lulu commented 6 years ago

@CookPete Thank you very much. componentDidUpdate(){ console.log(this.rp.player.player); const audio = this.rp.player.player; audio.load(); audio.play(); } I solved the problem through this