ap4y / OrigamiEngine

Lightweight audio engine for iOS and OSX with flac, cue, mp3, m4a, m3u support.
http://ap4y.github.com/OrigamiEngine/
MIT License
545 stars 117 forks source link

It takes noticeable time to prepare long audio file to play #26

Closed HiveHicks closed 10 years ago

HiveHicks commented 10 years ago

I'm trying to use OrigamiEngine to play long audio files (duration > 1 hour). But for some of them it may take some time between the call to playUrl: and the moment when the engine actually starts playing. In my case it was 5 seconds in simulator and 40 seconds on the device (iPhone 4S).

The line that's causing the delay is in CoreAudioDecoder.m, line 157:

    err  = ExtAudioFileGetProperty(_in,
            kExtAudioFileProperty_FileLengthFrames,
            &size,
            &total);
ap4y commented 10 years ago

I guess you are trying to play mp3 file over the http protocol. The situation is ExtAudioFileGetProperty used to get minimal amount of information, like frames count, bit rate etc. Without this information it won't be possible to determine the length of the track. Unfortunately, some formats (like mp3) require access to the last bytes of the file to determine frame count. This is different for the flac for example, because STREAMINFO metadata contains total number of samples in first bytes. The problem is HTTP protocol by default (and library implementation) doesn't support random access, so in order to access to the latest bytes the whole file have to be downloaded. It can be avoided by using Content-Range/Range access, but it requires support from the server that is serving this file, and unfortunately it doesn't supported in some network media players and upnp servers. If you intend to interact with API or you are building custom REST service you may consider storing some metadata on the server and sending to the client (I did that with one of my projects). Perfect solution will be checking for Range access support from the backend and use random access and fallback to regular operation otherwise. It's a bit time consuming operation, I would like to add support for range access and some HTTP streaming formats, but it will take a time and I don't have ETA right now of this feature.

HiveHicks commented 10 years ago

The mp3 I'm trying to play is a local file which is located in documents directory and is 2 hours long.

If I use AVAudioPlayer, it starts playing almost immediately.

koztay commented 10 years ago

I also have the same problem for long MP3 files over http. And If I use AVAudioPlayer, it starts playing almost immediately.

ap4y commented 10 years ago

Can I get access to this file? I will check what can be the problem with it.

koztay commented 10 years ago

Hi Arthur, The file link is as follows: https://www.dropbox.com/d/bar8vdyc8nbymib/vivaldi.mp3 I am trying to play it with my iOS application which uses OrigamiEngine and streaming link with Dropbox API and it never starts until it is downloaded completely. The streaming links dead in every 4 hours so I don't send you the streaming link. But if you need it, I also can send the streaming link. I think the problem is with MP3 files which don't contain any metadata. Because I am also having more loading times for standard 4-5 minutes MP3 files without metadata than MP3 files with metadata. So, I am thinking that if the MP3 file does not contain any metadata, it downloads the whole file first. While the file size is around 4-5 MB so the user has not been effected very much, because it can be downloaded around max. 10-15 seconds in high speed networks. But you are the coder, so maybe I am wrong. Thanks in advance. Best Regards,

On 25Fe b, 2014, at 00:44, Arthur Evstifeev notifications@github.com wrote:

Can I get access to this file? I will check what can be the problem with it.

— Reply to this email directly or view it on GitHub.

ap4y commented 10 years ago

Streaming problem with mp3 was roughly discussed in my first comment in this thread. I will take a look once again, maybe I will be able to solve problem a bit differently. Problem with local files is a bit concerning though.

koztay commented 10 years ago

I have tested several MP3 files as streaming from Dropbox. The result I got is as follows: If the MP3 files has album image in metadata it plays shortly. But if not it does not play.

nickcheng commented 10 years ago

Any update? I have a MP3 file also has the same problem. DELETED LINK

Every time I play this file with ORGMEngine, it'll download all parts of file.

ap4y commented 10 years ago

hey @nickcheng, no global updates so far, I'm not sure how to resolve this issue conceptually. I'll check your file tomorrow, will see what I can do for you specific situation.

nickcheng commented 10 years ago

Thanks @ap4y

koztay commented 10 years ago

The fix did not solve my problem. It does not work for my following url : http://www.karnas.com.tr/misc/vivaldi.mp3 (file size approx 50MB and no ID3 tags) but it works properly for this one: http://www.karnas.com.tr/misc/rodstewart.mp3 (file size approx 7MB with ID3 tags)

ap4y commented 10 years ago

Hey @koztay, this fix wasn't complete by any means it was generally targeted to the problem with specific file. I'm reopening this issue and will check your files over the weekend. Thanks for the report.

koztay commented 10 years ago

Thanks in advance @ap4y

ap4y commented 10 years ago

I checked your files, with this fix they are playing without delay.

koztay commented 10 years ago

Thanks you very much @ap4y . It works now without delay.

koztay commented 10 years ago

Dear @ap4y , Now I am having problem with the following mp3 file : http://www.karnas.com.tr/misc/ayrilikyamankelime.mp3 This file does not play.

ap4y commented 10 years ago

I will check it over the weekend

ap4y commented 10 years ago

Hey @koztay I checked you file and it contains broken id3v2 tag. I had several similar reports, for example in #21. You can easily check your file with hex editor.

koztay commented 10 years ago

Hi @ap4y , I checked the file with core audio methods and the file plays without any error. First I tried AVAudioPlayer for local play it played correctly. After I tried it with AVPlayer with the URL above and it also worked properly but with a couple of seconds delay which is normal for AVPlayer. So, example in #21 does not explain the situation.

ap4y commented 10 years ago

Hi @koztay. I mentioned this in #21:

Some codecs can handle that, they are looking for sync frame after provided location, 
but it's not the case for CoreAudio

In this case by CoreAudio I mean ExtFile API. I could potentially fix that issue, but it's not a trivial fix to implement for APIs that I use. I could potentially use different codec for mp3 files, but it will bring additional overhead to the library, since ExtFile available on all Apple platforms.

I personally see disadvantages of both solutions and considering the fact that files (specifically id3 tag) are not formatted according to the specification, it feel like it's not worth solving this issue at this moment. I would suggest you to create a new github issue and maybe in future I will find a better solution for this problem.

koztay commented 10 years ago

Hi @ap4y , I understand the situation, nevertheless I don't find a reasonable explanation how metatags causes not playing the file. I mean such cases could result metadata unavailable, thats OK! but as I said again, I don't understand how apple engineers can write such bad code which results the file non playable instead of ignoring metadata in such cases. Thank you very much.

ap4y commented 10 years ago

I don't know why this APIs behave like this with files with incorrect id3v2 tag. I can only guess that it can be inefficient to traverse file in order to find first correct frame. Additionally, size field from id3v2 tag header provided for simple reason, to point to the actual audio data, again for faster decoding. In your case this information is incorrect. You can easily check it yourself: AudioFileOpenWithCallbacks that I used to initialise render cycle returns error typ? after trying to read data at offset 35993. In you case header contains size of 00 02 19 0F which is encoded value of 35983, size of the header is 10 bytes, so it gives you exactly 35993. Everything happens according to the mp3 with id3v2 tag specification.

As I already suggested, I think you should create separate issue. Maybe someone will be able to resolve this situation. There is a chance that I missed something in this case or don't know a proper API.

koztay commented 10 years ago

Thank you @ap4y, I created a new issue.