TheWidlarzGroup / react-native-video

A <Video /> component for react-native
https://thewidlarzgroup.github.io/react-native-video/
MIT License
7.18k stars 2.89k forks source link

ERROR_CODE_IO_BAD_HTTP_STATUS while trying to stream m3u8. #2899

Closed sujaldev closed 1 year ago

sujaldev commented 2 years ago

Bug

Problem

I'm trying to stream a m3u8 file in a react native app (for android TV) and I'm getting this error:

 LOG  {"error": {"errorCode": "22004", "errorException": "com.google.android.exoplayer2.ExoPlaybackException: Source error", "errorStackTrace": "com.google.android.exoplayer2.ExoPlaybackException: Source error
    at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:632)
    at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:604)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:223)
    at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 403
    at com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource.open(OkHttpDataSource.java:329)
    at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:258)
    at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84)
    at com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:99)
    at com.google.android.exoplayer2.upstream.DataSourceInputStream.open(DataSourceInputStream.java:62)
    at com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:174)
    at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:923)
", "errorString": "ExoPlaybackException: ERROR_CODE_IO_BAD_HTTP_STATUS"}}

I don't know java so from the above traceback I'm guessing that the server is responding with an HTTP 403 and therefore it is unable to stream the file.

What I've tried

I decided to ssh into my android TV and directly use curl to fetch the m3u8 file and it responds with this:

curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Moreover, many of the issues I found on github having a similar problem contain a URL that gives the same response when fetched directly with curl. Interestingly, if I use the fetch API in JS to console log the response from the m3u8 url, it works perfectly. So I'm guessing the problem is somewhere in exoplayer.

Platform

Which player are you experiencing the problem on:

Environment info

React native info output:

 System:
    OS: Linux 5.19 Fedora Linux 36 (Workstation Edition)
    CPU: (12) x64 AMD Ryzen 5 3600 6-Core Processor
    Memory: 4.93 GB / 7.66 GB
    Shell: 5.2.2 - /bin/bash
  Binaries:
    Node: 16.18.0 - ~/.nvm/versions/node/v16.18.0/bin/node
    Yarn: Not Found
    npm: 8.19.2 - ~/.nvm/versions/node/v16.18.0/bin/npm
    Watchman: 20221016.020512.0 - /usr/local/bin/watchman
  SDKs:
    Android SDK: Not Found
  IDEs:
    Android Studio: Not Found
  Languages:
    Java: Not Found
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.0.0 => 18.0.0 
    react-native: Not Found
    react-native-tvos:  0.69.6-0 
  npmGlobalPackages:
    *react-native*: Not Found

NOTE I don't know why it's saying Java, Android SDK and Android Studio are not installed, I have all of them installed and Android SDK is configured through a local.properties file.

Library version: 6.0.0-alpha.3

Steps To Reproduce

  1. Create a component that returns the following:
    <Video
      style={{flex: 1, width: '100%', height: '100%', backgroundColor: 'green'}}
      source={{uri: url, type: 'm3u8'}} // replace url
      ref={ref => (this.player = ref)}
      onError={err => console.log(err)}
    />
  2. Run the app

Expected behaviour

  1. Video plays and does not give any errors

Reproducible sample code

I think this isn't really required as there's nothing much in the code.

freeboub commented 2 years ago

Thank you for the detailed description! but without stream url, it is hard to investigate the issue. type: 'm3u8' is mandatory if you have an exotic url format. According to the description, you have a ssl error (SSL certificate problem: certificate has expired) but also an error 403 Forbidden from logcat: like an authorization issue due to missing token of something similar.

I think you should have a look to charles trace to understand how exoplayer behaves exactly.

sujaldev commented 2 years ago

but without stream url, it is hard to investigate the issue.

Sorry I didn't include the m3u8 URL because it keeps changing and also I'm scraping it off of a piracy website so I don't know if people would be okay with opening that, but if that's not a problem I can share a URL here. I don't know for how long this would be valid but you can ping me and I'll regenerate the URL or if you prefer you can use this API I wrote to generate the m3u8 URL.

type: 'm3u8' is mandatory if you have an exotic url format.

What would count as "exotic" here? The URL does have a lot of GET parameters. It also has the .m3u8 extension after the file name so pretty standard I think...

like an authorization issue due to missing token of something similar.

The only way I see that happening is if the code responsible for making the request is somehow dropping some GET parameters. This was happening when I used curl to make a request but I thought that was due to bash's syntax and surrounding the URL in quotes fixed it. Another thing I want to mention is that I used an emulator in android studio and monitored the network activity and it seems like a request to the m3u8 URL is never made so how can one get a HTTP 403 without even making a request?

charles trace

Sorry I don't know what that is. Are you talking about Charles web proxy? If I understand correctly you're suggesting I look in the logs of the server serving the m3u8 file right? If yes, I'm not in control of the server so that wouldn't be possible.

freeboub commented 2 years ago

Hello, the url provided already generate an error 403... For the 'exotic' url format, I mean exoplayer is not able to detect stream type if the url doesn't finish with m3u8 For charles trace, please have a look to this page: https://github.com/react-native-video/react-native-video/blob/master/docs/DEBUGGING.md

Finnally, if your url become invalid after a while, you will not be able to stream the content sucessfully. I think your url have a token t=nMm4EzARW539CA0oczH8McTp7nNLSCKz8tcGx3YyPAI . It is not possible to update url 'on the fly' to continue stream without interuption.

sujaldev commented 2 years ago

Hello, the url provided already generate an error 403...

How did you check? It's still working for me. I visited the page directly in my browser which tries to download the m3u8 file and I also tried to stream this with mpv and vlc which also worked.

It is not possible to update url 'on the fly' to continue stream without interuption.

I think it stays valid long enough to complete the duration of a stream. Even if it does not, it should at least work for 10 minutes but even that is not working...

sujaldev commented 1 year ago

For charles trace, please have a look to this page:

Hi, I think I might have figured it out. I used the proxy to see the network request and it seems like exoplayer is setting a user agent parameter in the request which seems to be causing the 403.

image

Do you know how can I remove this header?

sujaldev commented 1 year ago

Nvm found it in the docs, thank you for your help!

chienduc91 commented 1 year ago

Nvm found it in the docs, thank you for your help!

@sujaldev how did you handle it please let me know

sujaldev commented 1 year ago

Yeah sure, I just set a different user-agent in headers like this:

<VideoPlayer
  source={{
    uri: "your url",
    type: 'm3u8',
    headers: {
      'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
    },
  }}
/>
raginisahu commented 1 year ago

I'm facing the same issue for the below url : https://vz-7abd54ba-64a.b-cdn.net/64417fd1-2628-40d9-9f89-2f67dd5b821a/playlist.m3u8?v=1690986908

I tried to play with other media player it is working fine.

the error code is "22004".

TechSpace4532 commented 4 days ago

I'm facing the same issue of "ExoPlaybackException: ERROR_CODE_IO_BAD_HTTP_STATUS" with error code "22004" and also app getting crash after few seconds my code is as below, I'm using video_url as AWS s3 bucket url's, please give me the solution as I have tried most of the ways given in other bugs and trying since 4 days to resolve...

I'm using "Android 11, 12 physical devices", and simulator's for testing

<VideoPlayer videoRef={videoRef} onBuffer={onBuffer} onError={onError} key={index} repeat={true} resizeMode="cover" paused={currentIndex == index && isFocused ? false : true} source={{ uri: isFocused ? item.video_url : null, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36', }, }} muted={mute} reportBandwidth rate={1} playInBackground disableFocus playWhenInactive={false} ignoreSilentSwitch="ignore" progressUpdateInterval={2500} allowExternalPlayback automaticallyWitsToMinimizeStalling={false} bufferConfig={{ minBufferMs: 15000, maxBufferMs: 50000, bufferForPlaybackMs: 2500, bufferForPlaybackAfterRebufferMs: 5000, }} useTextureView={false} minLoadRetryCount={5} selectedVideoTrack={{ type: 'resolution', value: 480, }} style={{ width: "100%", height: '100%', }} />