You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] Streaming Audio takes too long to load and stream #575
I have an issue with streaming audio with Readium. I have an audio file that takes 30 seconds to load the Publication object and another 20 seconds to start streaming after calling the play method.
I don't know if I am doing something wrong.
I attached a sample project that reproduces the issue
I am using Swift 6
Any help is appreciated. Thank you
How to reproduce?
Open the Sample project
Run it on a simulator or device of your choice (running in the preview also works)
You have to wait for 30 seconds until you can play the file
You have to wait at least 20 seconds until the playback starts
Readium version
3.2.0
OS version
iOS 17.6+
Testing device
Any device of emulator
Environment
macOS: 15.4
platform: arm64
Xcode 16.3
Build version 16E140
@mickael-menu thank you for your reply. I don't know, maybe the server was down at that time, the link works for me, and it's part of a website. It's an audio of more than one hour of playback, which takes a lot of time to start.
I implement my AVPlayer logic, and the playback begins immediately. Strangely, Readium takes so long to load the file and then play it. Even for smaller audio files like this Audio File, it still takes a few seconds to load, whereas when I use the AVPlayer directly, it's instantaneously.
I did a little debugging and the open publication code is stuck for 30 seconds (with the original audio) in this method private func makeReadingOrder(for container: Container) async -> Result<[(AnyURL, Format)], PublicationParseError> after that it's considered loaded, but it still takes several seconds to play.
Thank you again for your reply and I will check the other issue.
@mickael-menu I think I figured out the issue.
When retrieving the metadata from a remote resource using this line let asset = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true]) takes a long time to load since we are requesting the precise audio duration.
Based on the Apple documentation, the default value should be enough, but I am unsure since I don't know the entire implementation.
Setting a value of true indicates longer loading times are acceptable in cases where you require precise timing. Container formats like QuickTime and MPEG-4 provide sufficient timing information and don’t require additional parsing to retrieve it. Other formats don’t provide sufficient summary information, and the system can’t accurately calculate the resource’s duration and timing without examining the media content.
If you only intend to play the asset, the default value of false is sufficient because AVPlayer supports approximate random access by time when full precision isn’t available.
Removing that option makes the metadata load much faster. I believe that when a remote asset is loaded, the code shouldn't block the execution for the metadata to be fully loaded before the audio is ready to play. The audio can be played immediately, and the metadata can be loaded in the background. I am not sure how to achieve that at the moment since there are many parts of the code relying on the metadata.
Thank you for your on-going investigation on this issue. I took a look today and have some observations:
There is definitely something wrong with the URL https://davidjares.eu/wp-content/uploads/2025/04/01-Prolog-Cesta-z-ni%CC%81z%CC%8C-neni%CC%81-na%CC%81vratu.mp3. Now it works, but it takes ~30 secondes to answer to a HEAD request from Swift (interestingly a GET request is much faster). From my benchmarking this is the reason it takes a while to open a publication with this URL, it gets stuck in the DefaultHTTPClient in the receiveChallenge step. You can test it with this script to be run with swift script.swift:
The second URL you shared opens quickly for me, under a second (https://github.com/dimitris-c/sample-audio/raw/main/bensound-jazzyfrenchy-optimized.m4a). It might be slower than using AVPlayer because Readium has to sniff the format of the URL you provide to the AssetRetriever to know what type of publication it is. If you already know the format, you can pass it to the AssetRetriever to skip a bunch of HTTP requests.
For your last suggestion regarding AVURLAssetPreferPreciseDurationAndTimingKey I'm really confused. It should not be called when streaming a remote HTTP URL, as you can see here (the fileURL):
This is what I observed when running the test using the URLs you provided. We do need the precise duration because this code fills in the metadata in the Link objects. If you don't need it, you can provide a different implementation of the AudioPublicationManifestAugmentor when creating an AudioParser.
I took a look at your original code and I'm confusing with why you are creating a Container yourself from a single URL:
If you have a single resource (e.g. audio file), you don't need to create a Container, you can open the URL directly with the AssetRetriever. It knows how to load HTTP URLs if you provided an HTTPClient when creating the AssetRetriever.
Let me know if I'm missing something and you still think there is something wrong with Readium, I'll reopen the issue.
Activity
mickael-menu commentedon Apr 23, 2025
The URL in the project you shared does not seem to be available anymore (the server timed out)
https://davidjares.eu/wp-content/uploads/2025/04/01-Prolog-Cesta-z-ni%CC%81z%CC%8C-neni%CC%81-na%CC%81vratu.mp3
It might be a server issue if your server is too slow to return the bytes. Otherwise I think it might be a duplicate of this other issue: #579
audioBook.lcpl) – Chunks Fully Buffered Before Playback Starts #579dsilva-adastra commentedon Apr 23, 2025
@mickael-menu thank you for your reply. I don't know, maybe the server was down at that time, the link works for me, and it's part of a website. It's an audio of more than one hour of playback, which takes a lot of time to start.
I implement my AVPlayer logic, and the playback begins immediately. Strangely, Readium takes so long to load the file and then play it. Even for smaller audio files like this Audio File, it still takes a few seconds to load, whereas when I use the AVPlayer directly, it's instantaneously.
I did a little debugging and the open publication code is stuck for 30 seconds (with the original audio) in this method
private func makeReadingOrder(for container: Container) async -> Result<[(AnyURL, Format)], PublicationParseError>after that it's considered loaded, but it still takes several seconds to play.Thank you again for your reply and I will check the other issue.
mickael-menu commentedon Apr 25, 2025
Thank you for investigating, that's really helpful. I will try to take a look into the
makeReadingOrdercode next week.dsilva-adastra commentedon Apr 28, 2025
@mickael-menu I think I figured out the issue.
When retrieving the metadata from a remote resource using this line
let asset = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])takes a long time to load since we are requesting the precise audio duration.Based on the Apple documentation, the default value should be enough, but I am unsure since I don't know the entire implementation.
Removing that option makes the metadata load much faster. I believe that when a remote asset is loaded, the code shouldn't block the execution for the metadata to be fully loaded before the audio is ready to play. The audio can be played immediately, and the metadata can be loaded in the background. I am not sure how to achieve that at the moment since there are many parts of the code relying on the metadata.
mickael-menu commentedon Apr 30, 2025
Thank you for your on-going investigation on this issue. I took a look today and have some observations:
There is definitely something wrong with the URL https://davidjares.eu/wp-content/uploads/2025/04/01-Prolog-Cesta-z-ni%CC%81z%CC%8C-neni%CC%81-na%CC%81vratu.mp3. Now it works, but it takes ~30 secondes to answer to a
HEADrequest from Swift (interestingly aGETrequest is much faster). From my benchmarking this is the reason it takes a while to open a publication with this URL, it gets stuck in theDefaultHTTPClientin thereceiveChallengestep. You can test it with this script to be run withswift script.swift:The second URL you shared opens quickly for me, under a second (https://github.com/dimitris-c/sample-audio/raw/main/bensound-jazzyfrenchy-optimized.m4a). It might be slower than using
AVPlayerbecause Readium has to sniff the format of the URL you provide to theAssetRetrieverto know what type of publication it is. If you already know the format, you can pass it to theAssetRetrieverto skip a bunch of HTTP requests.For your last suggestion regarding
AVURLAssetPreferPreciseDurationAndTimingKeyI'm really confused. It should not be called when streaming a remote HTTP URL, as you can see here (thefileURL):swift-toolkit/Sources/Streamer/Parser/Audio/AudioPublicationManifestAugmentor.swift
Line 31 in 9ab5721
Linkobjects. If you don't need it, you can provide a different implementation of theAudioPublicationManifestAugmentorwhen creating anAudioParser.I took a look at your original code and I'm confusing with why you are creating a
Containeryourself from a single URL:If you have a single resource (e.g. audio file), you don't need to create a
Container, you can open the URL directly with theAssetRetriever. It knows how to load HTTP URLs if you provided anHTTPClientwhen creating theAssetRetriever.Let me know if I'm missing something and you still think there is something wrong with Readium, I'll reopen the issue.