Search code examples
androidreact-nativesslssl-certificatereact-native-video

React native video unable to play m3u8 file


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

  • This one is not much of a solution but I tried switching to the react-native-video-player instead of react-native-video but that didn't work.
  • I tried passing the type: 'm3u8' and type: 'hls' inside the source attribute of the video tag along with the uri and this didn't help at all.
  • Tried to check if another m3u8 url (i.e. from another domain/server) is working, and it is working.
  • Downgrading react-native-video version, problem persists with different error message.

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.

Specs

  • react-native : 'npm:[email protected]'
  • react-native-video : '^6.0.0-alpha.3'
  • Android TV : Tested both on a Raspberry Pi running Android TV (LineageOS I think) and an actual android tv set top box with same results.

Solution

  • The issue was with the user-agent header, exoplayer was setting a user-agent which was causing an HTTP 403. I had to use a proxy to figure this out and still have no clue as per why android studio was not showing the request that had an error.