google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.74k stars 6.03k forks source link

Exoplayer unable to play some mp3 files from url but successfully plays it from storage. #7452

Closed deepaksingh16 closed 4 years ago

deepaksingh16 commented 4 years ago

Issue description

Unable to play song from url but it can be played from storage. And in some cases exact opposite of scenario happens as well. The file can be played on chrome browser and other players but only exoplayer gives the exception that none of the available extractors could read the stream.

Link to test content

As the links contain authentication token, therefore sending the links via Email

A full bug report captured from the device

2020-06-01 18:12:07.746 6955-7190/com.medialeap E/ExoPlayerImplInternal: Source error. com.google.android.exoplayer2.source.UnrecognizedInputFormatException: None of the available extractors (MatroskaExtractor, FragmentedMp4Extractor, Mp4Extractor, Mp3Extractor, AdtsExtractor, Ac3Extractor, TsExtractor, FlvExtractor, OggExtractor, PsExtractor, WavExtractor, AmrExtractor, Ac4Extractor, FlacExtractor) could read the stream. at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractorHolder.selectExtractor(ProgressiveMediaPeriod.java:1059) at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:947) at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:381) 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:764)

Version of ExoPlayer being used

r2.10.1

Device(s) and version(s) of Android being used

The issue can be reproduced on any Android device. The Android OS that I've tested are: Android 9.0

andrewlewis commented 4 years ago

The MP3 link provided via email doesn't play either loaded over HTTP or when pushed to storage having been downloaded via curl, because the sniffing operation fails to find a valid MPEG audio frame. I checked the first few candidate header bytes and they were in the same reading over HTTP and locally.

How are you playing the stream from storage?

deepaksingh16 commented 4 years ago

@andrewlewis I'am using file path uri to create MediaSource(ProgressiveMediaSource) for Player. FYI, I'am also using FFMPEG and Flac extensions with EXTENSION_RENDERER_MODE_PREFER for DefaultRenderersFactory

andrewlewis commented 4 years ago

Could you email a link to the downloaded stream? I'd like to check what the difference in the bytes read by the extractor are in the two cases. In my testing I saw the same error with the downloaded stream.

deepaksingh16 commented 4 years ago

@andrewlewis Sent an email with download link

andrewlewis commented 4 years ago

I get a 'unauthorized' error for the second link so I can't compare it to what the server sends for the first link. If you download the audio from the link from your first email then push that to the device, does it play correctly for you?

deepaksingh16 commented 4 years ago

The audio from first link is working after downloading. Can you please download audio from first link through browser? And see if it works for you as I am able to play it after downloading. Tested multiple times on different devices and the result is same.

Edit: The link in the first mail and the download link(Faulty one in second mail) points to same source. So, you can use first one to download.

andrewlewis commented 4 years ago

I see the same thing whether the file is downloaded from browser or using curl and pushed to the device and played via a file URL, and when loading it from the HTTP URL directly: in all cases the stream doesn't have valid MPEG audio frames. If you download the stream then put it on Google Drive or similar then I can see what is different. The stream I am getting has md5 1ed38752255b788829baef185c9460bd.

deepaksingh16 commented 4 years ago

Sent you an email with drive link.

andrewlewis commented 4 years ago

The file shared via drive is different from what the server is sending. Even the file sizes are different.

% curl "[url shared via email]" --output fromserver.mp3
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 2557k  100 2557k    0     0   436k      0  0:00:05  0:00:05 --:--:--  546k
% md5 fromserver.mp3 
MD5 (fromserver.mp3) = 1ed38752255b788829baef185c9460bd
% md5 fromdrive.mp3 
MD5 (fromdrive.mp3) = da35214d947cc512376fb60557bf871a

I don't have an explanation for why we are seeing different behavior but from my side this just looks like the MP3 stream from the server is bad. If you can provide more evidence that the problem is within ExoPlayer I'll reopen the issue.

deepaksingh16 commented 4 years ago

@andrewlewis I've sent a Google drive link of song downloaded directly from streaming link(From Mail 1). This is the same source by which I'am able to play song in ExoPlayer when downloaded to phone storage. Can you please check now?

andrewlewis commented 4 years ago

For me, it doesn't play in the 2.10.1 demo app, with the same UnrecognizedInputFormatException, and has the same md5sum as fromserver.mp3 in my previous message.

deepaksingh16 commented 4 years ago

@andrewlewis I created a separate demo to choose file locally and played the file downloaded from stream url and it works fine. I am getting UnrecognizedInputFormatException only in case of playing it through url. I am preparing media by following code:

private void prepareExoPlayerFromFileUri(Uri uri){
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(null), new DefaultLoadControl());
        exoPlayer.addListener(eventListener);
        DataSpec dataSpec = new DataSpec(uri);
        final FileDataSource fileDataSource = new FileDataSource();
        try {
            fileDataSource.open(dataSpec);
        } catch (FileDataSource.FileDataSourceException e) {
            e.printStackTrace();
        }
        DataSource.Factory factory = new DataSource.Factory() {
            @Override
            public DataSource createDataSource() {
                return fileDataSource;
            }
        };
        MediaSource audioSource = new ExtractorMediaSource(fileDataSource.getUri(),
                factory, new DefaultExtractorsFactory(), null, null);
        exoPlayer.prepare(audioSource);
        initMediaControls();
    }

I am pretty sure that there is no issue with file and even with stream as all other Media Players are able to play file as well as url but only Exoplayer is giving error. In order to check if stream is giving correct data, you can play url from first email in browser as well(Tested in google chrome browser). If there would be any issue in stream then i assume even browser won't be able to play it. Right?

deepaksingh16 commented 4 years ago

@andrewlewis Can you please provide an update on this? Its a bit important for us to get pass this issue as we were on point of releasing the app. I'll be grateful if you can give it another shot.

andrewlewis commented 4 years ago

The factory in your code snippet always returns the same instance, so you should probably use FileDataSourceFactory or DefaultDataSourceFactory instead. Please try that first in case it fixes the issue.

If not, do you see the same behavior using the ExoPlayer demo app using the latest release (rather than your own demo app)? There is documentation on playing your own content.