SInt64 SFB::Audio::CoreAudioDecoder::_GetCurrentFrame() const { if(mUseM4AWorkarounds) return mCurrentFrame; SInt64 currentFrame = -1; OSStatus result = ExtAudioFileTell(mExtAudioFile, ¤tFrame); if(noErr != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileTell failed: " << result); return -1; } return currentFrame; }
int64_t ExtAFSource::getPosition() { int64_t pos; CHECKCA(ExtAudioFileTell(m_eaf, &pos)); return pos; }
bool SFB::Audio::CoreAudioDecoder::_Open(CFErrorRef *error) { // Open the input file OSStatus result = AudioFileOpenWithCallbacks(this, myAudioFile_ReadProc, nullptr, myAudioFile_GetSizeProc, nullptr, 0, &mAudioFile); if(noErr != result) { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileOpenWithCallbacks failed: " << result); if(error) { SFB::CFString description = CFCopyLocalizedString(CFSTR("The format of the file “%@” was not recognized."), ""); SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("File Format Not Recognized"), ""); SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } return false; } result = ExtAudioFileWrapAudioFileID(mAudioFile, false, &mExtAudioFile); if(noErr != result) { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileWrapAudioFileID failed: " << result); if(error) { SFB::CFString description = CFCopyLocalizedString(CFSTR("The format of the file “%@” was not recognized."), ""); SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("File Format Not Recognized"), ""); SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; return false; } // Query file format UInt32 dataSize = sizeof(mSourceFormat); result = ExtAudioFileGetProperty(mExtAudioFile, kExtAudioFileProperty_FileDataFormat, &dataSize, &mSourceFormat); if(noErr != result) { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileGetProperty (kExtAudioFileProperty_FileDataFormat) failed: " << result); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } // Tell the ExtAudioFile the format in which we'd like our data // For Linear PCM formats, leave the data untouched if(kAudioFormatLinearPCM == mSourceFormat.mFormatID) mFormat = mSourceFormat; // For Apple Lossless, convert to high-aligned signed ints in 32 bits else if(kAudioFormatAppleLossless == mSourceFormat.mFormatID) { mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsAlignedHigh; mFormat.mSampleRate = mSourceFormat.mSampleRate; mFormat.mChannelsPerFrame = mSourceFormat.mChannelsPerFrame; if(kAppleLosslessFormatFlag_16BitSourceData == mSourceFormat.mFormatFlags) mFormat.mBitsPerChannel = 16; else if(kAppleLosslessFormatFlag_20BitSourceData == mSourceFormat.mFormatFlags) mFormat.mBitsPerChannel = 20; else if(kAppleLosslessFormatFlag_24BitSourceData == mSourceFormat.mFormatFlags) mFormat.mBitsPerChannel = 24; else if(kAppleLosslessFormatFlag_32BitSourceData == mSourceFormat.mFormatFlags) mFormat.mBitsPerChannel = 32; mFormat.mBytesPerPacket = 4 * mFormat.mChannelsPerFrame; mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } // For all other formats convert to the canonical Core Audio format else { mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mSampleRate = mSourceFormat.mSampleRate; mFormat.mChannelsPerFrame = mSourceFormat.mChannelsPerFrame; mFormat.mBitsPerChannel = 32; mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; } result = ExtAudioFileSetProperty(mExtAudioFile, kExtAudioFileProperty_ClientDataFormat, sizeof(mFormat), &mFormat); if(noErr != result) { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileSetProperty (kExtAudioFileProperty_ClientDataFormat) failed: " << result); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } // Setup the channel layout // There is a bug in EAF where if the underlying AF doesn't return a channel layout it returns an empty struct // result = ExtAudioFileGetPropertyInfo(mExtAudioFile, kExtAudioFileProperty_FileChannelLayout, &dataSize, nullptr); result = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, &dataSize, nullptr); if(noErr == result) { auto channelLayout = (AudioChannelLayout *)malloc(dataSize); // result = ExtAudioFileGetProperty(mExtAudioFile, kExtAudioFileProperty_FileChannelLayout, &dataSize, mChannelLayout); result = AudioFileGetProperty(mAudioFile, kAudioFilePropertyChannelLayout, &dataSize, channelLayout); if(noErr != result) { // LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileGetProperty (kExtAudioFileProperty_FileChannelLayout) failed: " << result); LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileGetProperty (kAudioFilePropertyChannelLayout) failed: " << result); free(channelLayout); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } mChannelLayout = channelLayout; free(channelLayout); } else // LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileGetPropertyInfo (kExtAudioFileProperty_FileChannelLayout) failed: " << result); LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileGetPropertyInfo (kAudioFilePropertyChannelLayout) failed: " << result); // Work around bugs in ExtAudioFile: http://lists.apple.com/archives/coreaudio-api/2009/Nov/msg00119.html // Synopsis: ExtAudioFileTell() and ExtAudioFileSeek() are broken for m4a files AudioFileID audioFile; dataSize = sizeof(audioFile); result = ExtAudioFileGetProperty(mExtAudioFile, kExtAudioFileProperty_AudioFile, &dataSize, &audioFile); if(noErr != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileGetProperty (kExtAudioFileProperty_AudioFile) failed: " << result); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } AudioFileTypeID fileFormat; dataSize = sizeof(fileFormat); result = AudioFileGetProperty(audioFile, kAudioFilePropertyFileFormat, &dataSize, &fileFormat); if(noErr != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileGetProperty (kAudioFilePropertyFileFormat) failed: " << result); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } if(kAudioFileM4AType == fileFormat || kAudioFileMPEG4Type == fileFormat || kAudioFileAAC_ADTSType == fileFormat) mUseM4AWorkarounds = true; #if 0 // This was supposed to determine if ExtAudioFile had been fixed, but even though // it passes on 10.6.2 things are not behaving properly SInt64 currentFrame = -1; result = ExtAudioFileTell(mExtAudioFile, ¤tFrame); if(noErr != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileTell failed: " << result); result = ExtAudioFileDispose(mExtAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "ExtAudioFileDispose failed: " << result); result = AudioFileClose(mAudioFile); if(noErr != result) LOGGER_NOTICE("org.sbooth.AudioEngine.Decoder.CoreAudio", "AudioFileClose failed: " << result); mAudioFile = nullptr; mExtAudioFile = nullptr; return false; } if(0 > currentFrame) mUseM4AWorkarounds = true; #endif return true; }