androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.73k stars 415 forks source link

CacheWriter cant write cache. ErrnoException open failed: ENOENT #1570

Open Toxa2033 opened 4 months ago

Toxa2033 commented 4 months ago

Version

Media3 1.3.1

More version details

No response

Devices that reproduce the issue

Снимок экрана 2024-07-29 в 16 23 42 Снимок экрана 2024-07-29 в 16 23 52

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

There is an issue that on some devices CacheWriter can't save the cache to internal storage. I have not been able to reproduce the error, but I'm guessing the user just launched the .mp3 media by link.

Folder for SimpleCache: context.filesDir.resolve("audio-files")

Expected result

The media play successfully

Actual result

The user receives an error and playback stops.

StackTrace:

Caused by android.system.ErrnoException: open failed: ENOENT (No such file or directory)
       at libcore.io.Linux.open(Linux.java)
       at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
       at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
       at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
       at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:8523)
       at libcore.io.IoBridge.open(IoBridge.java:560)
       at java.io.RandomAccessFile.<init>(RandomAccessFile.java:289)
       at java.io.RandomAccessFile.<init>(RandomAccessFile.java:152)
       at androidx.media3.datasource.FileDataSource.openLocalFile(FileDataSource.java:186)
       at androidx.media3.datasource.FileDataSource.open(FileDataSource.java:116)
       at androidx.media3.datasource.DefaultDataSource.open(DefaultDataSource.java:275)
       at androidx.media3.datasource.TeeDataSource.open(TeeDataSource.java:54)
       at androidx.media3.datasource.cache.CacheDataSource.openNextSource(CacheDataSource.java:799)
       at androidx.media3.datasource.cache.CacheDataSource.open(CacheDataSource.java:612)
       at androidx.media3.datasource.cache.CacheWriter.readBlockToCache(CacheWriter.java:174)
       at androidx.media3.datasource.cache.CacheWriter.cache(CacheWriter.java:136)
       at androidx.media3.exoplayer.offline.ProgressiveDownloader$1.doWork(ProgressiveDownloader.java:106)
       at androidx.media3.exoplayer.offline.ProgressiveDownloader$1.doWork(ProgressiveDownloader.java:103)
       at androidx.media3.common.util.RunnableFutureTask.run(RunnableFutureTask.java:126)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
       at java.lang.Thread.run(Thread.java:1012)

Media

Normal .mp3 from a link like this https://example.com/ordinary.mp3

Bug Report

icbaker commented 4 months ago

From the description, this seems like a device-specific issue with file permissions, it seems unlikely it's related to the media3 library. By this I mean that if you tried to directly open a file in context.filesDir.resolve("audio-files") on one of these devices (without using any media3 code), then I would expect to see the same android.system.ErrnoException: open failed: ENOENT (No such file or directory) failure.

I'm afraid given that this doesn't look like a media3 issue, and it's not reproducible, there's not much we can do here. I'll leave this issue open for a couple of weeks. I would recommend you try reproducing on one of the devices you know to experience the problem. If you can reproduce it then it should be possible to see whether I'm right that it's not related to media3 (i.e. try with and without media3 code).

Toxa2033 commented 3 months ago

@icbaker Thank you for response. Finally I was able to find one case. Error not device specific.

Case:

  1. Using DownloadService to download a lot of media
  2. Delete all of them at once
  3. Quickly make a force stop the application
  4. Open the application

In this way everything from SimpleCache will be deleted, but the database will not have time to clean up completely and media3 will think that there are files that don't exist. At the next startup the database will be cleaned up and everything will work (tested already on media3 1.4). Maybe in the next version add on-the-fly check for the existence of a file and delete the record from the database if there is no such file and send the stream to upstream?

icbaker commented 3 months ago

Thanks for the extra detail and repro steps - @tianyif PTAL

tianyif commented 3 months ago

@Toxa2033,

Thanks for the follow up! Can you please clarify if the repro steps are for reproducing the stack trace in the description?

From the provided stack trace in the issue description -

at androidx.media3.datasource.FileDataSource.openLocalFile(FileDataSource.java:186)
       at androidx.media3.datasource.FileDataSource.open(FileDataSource.java:116)
       at androidx.media3.datasource.DefaultDataSource.open(DefaultDataSource.java:275)
       at androidx.media3.datasource.TeeDataSource.open(TeeDataSource.java:54)
       at androidx.media3.datasource.cache.CacheDataSource.openNextSource(CacheDataSource.java:799)
       at androidx.media3.datasource.cache.CacheDataSource.open(CacheDataSource.java:612)
       at androidx.media3.datasource.cache.CacheWriter.readBlockToCache(CacheWriter.java:174)
       at androidx.media3.datasource.cache.CacheWriter.cache(CacheWriter.java:136)
       at androidx.media3.exoplayer.offline.ProgressiveDownloader$1.doWork(ProgressiveDownloader.java:106)
       at androidx.media3.exoplayer.offline.ProgressiveDownloader$1.doWork(ProgressiveDownloader.java:103)

I'm seeing the issue happens when opening the upstream DataSource, then DefaultDataSource as the upstream data source has a FileDataSource open to get the upstream data. It looks like the dataspec passed to the upstream data source is a local file uri, and then something wrong when your local file is being accessed. Now I'm wondering what uri do you provide to your user when they are trying to play the downloaded media?

Back to the repro steps, I couldn't reproduce the issue on the demo app yet, and combined with some confusion in the stack trace, thus I have above questions. Looking forward to your reply!

Toxa2033 commented 3 months ago

@tianyif URI is not the path to the file, but the url link to the mp3 file. I suppose this happens because the files from the file system have been deleted, and the database has not had time to delete records about these files. It seems to me that media3 wants to download the file, but sees that there is something about it in the database, and probably tries to start caching data to a file that doesn't exist. If you need I can mail the database exoplayer_internal.db at the moment when the files are no longer there, but there are still records about them in the database

tianyif commented 3 months ago

@Toxa2033,

but sees that there is something about it in the database, and probably tries to start caching data to a file that doesn't exist

However, by point of the provided stack trace, the CacheDataSource behind the CacheWriter is still at the stage of opening the upstream, rather than trying to write to the cache yet.

Would you like to share your sample project with us via sending it to android-media-github@google.com?