CoreAudioFormat doesn't read MP3 file, QuickTime Player does

On OSX 10.10.5, JUCE fails to load some MP3 files like this one (please unpack the ZIP file). I’ve debugged the call to AudioFormatManager::createReaderFor, and I see that it calls CoreAudioFormat::createReaderFor, which returns nullptr. The file plays correctly in Quicklook and QuickTime Player.

Well, not really sure what we could do about that! We’re rather at the mercy of CoreAudio. The only alternative would be for you to use ffmpeg, but that far too huge a dependency for us to embed it in juce.

Okay. Thanks for the reply.

There is something wrong with the code, because this particular MP3 works with 100% of all MP3 players, including core audio. It just doesn’t work with the Juce code. My feeling is that there is something with the code. MP3 reading is the most basic of functions.

The same MP3 works in iTunes, QuickLook and QuickTime, which uses CcoreAudio.

Can you please take another look at it.

Take another look at what…??. We call a CoreAudio function that attempts to decode a file, and it either succeeds or fails.

It’s not clear why it would fail to open a particular file when Apple clearly have a codec that can handle it, but I’ve never seen anything in the API that enables or disables support for formats.

FYI I stepped into the code, and it does just fail in CoreAudio - there’s a call to AudioFileOpenWithCallbacks which just returns the error code ‘kAudioFileUnsupportedFileTypeError’

If there’s some magic that can be used to add extra codecs to CoreAudio then please let us know and we’ll enable it, but this doesn’t seem like something our code is doing wrong.

Thanks…We will figure it out. It’s weird. We may just have to use QuickTime or AVFoundation as a fallback. I definitely don’t want to delve into the confusing world of ffmpeg.

You should avoid QuickTime - that’s deprecated and won’t be an option much longer.

Hmm, I guess it could be that there are newer AVFoundation functions that may provide more codecs than the function we were using (which is part of AudioToolbox). No idea why it wouldn’t all be the same but if you find there is a different function that works, let us know and maybe we could switch to using that.

I’ve recently encountered this issue too. Some mp3 files I’m trying to load return kAudioFileUnsupportedFileTypeError from AudioFileOpenWithCallbacks(). The same files load in QuickTime Player, Amadeus Pro and other CoreAudio based apps.

There is a workaround. The ‘inFileTypeHint’ argument of CoreAudio::AudioFileOpenWithCallbacks() can be used to offer a hint to CoreAudio as to the type of file being passed in.

In this case if I pass kAudioFileMP3Type as the file type hint then the mp3 loads properly. It seems CoreAudio isn’t always able to identify mp3 files for whatever reason. Passing the mp3 hint doesn’t seem to affect loading m4a, AAC files etc.

4 Likes

Great find

Just encountered this, loading some mp3 file would not work.
Adding kAudioFileMP3Type indeed works and does not seem to affect other formats.
But it wouldn’t surprise me if it breaks other edge cases (files with incomplete headers or something) where AudioFileOpenWithCallbacks would figure out the format correctly, but would now try to open it as a mp3 all the time, thus failing on them.

@reuk would there be any way to provide the format information to AudioFileOpenWithCallbacks? It seems complicated since CoreAudioReader and even AudioFormatManager::createReaderFor have no clue about the file extension. But it would be a great addition since it would make the best use of the AudioFileOpenWithCallbacks function.

I’ve added this change here:

Note that no hint will be provided by default. If you want to load an mp3 file with CoreAudio, you’ll need to construct your own instance of CoreAudioFormat, passing in the appropriate format hint for the file you intend to read.

1 Like

That’s great, thanks @reuk !

I’ve also encountered this issue and managed to fix the problem following your advice

formatManager.registerFormat(new juce::CoreAudioFormat(juce::CoreAudioFormat::StreamKind::kMp3), false);

Now I also want to read m4a files and if I use the following function …

AudioFormatReader* AudioFormatManager::createReaderFor (std::unique_ptr<InputStream> audioFileStream)

… to create my reader, I can read m4a files with the CoreAudioFormat registered above (kMp3 hint)

However if i use this one …

AudioFormatReader* AudioFormatManager::createReaderFor (const File& file)

… I can’t read m4a files because there’s a check that won’t let m4a files pass

for (auto* af : knownFormats)
        if (af->canHandleFile (file))

So what I need to do is to register another CoreAudioFormat and pass it a kM4a hint, but that seems to give me an assertion, that I shouldn’t register the same format twice

Both solutions work fine, but it seems like there’s a bit of compromise for each one.

In the first case I need to make sure I will always call createReaderFor() with a unique_ptr to an InputStream and hope that the CoreAudioReader will never have problems to read a stream to an m4a file when given an mp3 hint.

In the second case I need to make sure I will always call createReaderFor with a File, and get used to hitting that assert for registering the same format twice.

What do you recommend?

p.s. I’m using JUCE v 6.1.4