Semaphore::Semaphore() { kern_return_t result = semaphore_create(mach_task_self(), &mSemaphore, SYNC_POLICY_FIFO, 0); if(KERN_SUCCESS != result) { LOGGER_CRIT("org.sbooth.AudioEngine.Semaphore", "semaphore_create failed: " << mach_error_string(result)); throw std::runtime_error("Unable to create the semaphore"); } }
void Guard::Signal() { int success = pthread_cond_signal(&mCondition); if(0 != success) { LOGGER_CRIT("org.sbooth.AudioEngine.Guard", "pthread_cond_signal failed: " << strerror(success)); throw std::runtime_error("Unable to signal the condition variable"); } }
Guard::Guard() { int success = pthread_cond_init(&mCondition, nullptr); if(0 != success) { LOGGER_CRIT("org.sbooth.AudioEngine.Guard", "pthread_cond_init failed: " << strerror(success)); throw std::runtime_error("Unable to initialize the condition variable"); } }
void Guard::Wait() { pthread_t currentThread = pthread_self(); if(!pthread_equal(mOwner, currentThread)) throw std::runtime_error("A thread is attempting to wait on a condition variable without a locked mutex"); mOwner = 0; int success = pthread_cond_wait(&mCondition, &mMutex); if(0 != success) { LOGGER_CRIT("org.sbooth.AudioEngine.Guard", "pthread_cond_wait failed: " << strerror(success)); throw std::runtime_error("Unable to wait for the condition variable"); } mOwner = currentThread; }
bool Guard::WaitUntil(struct timespec absoluteTime) { pthread_t currentThread = pthread_self(); if(!pthread_equal(mOwner, currentThread)) throw std::runtime_error("A thread is attempting to wait on a condition variable without a locked mutex"); mOwner = 0; int success = pthread_cond_timedwait(&mCondition, &mMutex, &absoluteTime); if(ETIMEDOUT != success && 0 != success) { LOGGER_CRIT("org.sbooth.AudioEngine.Guard", "pthread_cond_timedwait failed: " << strerror(success)); throw std::runtime_error("Unable to wait for the condition variable"); } mOwner = currentThread; return (ETIMEDOUT == success); }
bool SFB::Audio::TrueAudioDecoder::_Open(CFErrorRef *error) { mCallbacks = unique_callback_wrapper_ptr(new TTA_io_callback_wrapper); mCallbacks->iocb.read = read_callback; mCallbacks->iocb.write = nullptr; mCallbacks->iocb.seek = seek_callback; mCallbacks->decoder = this; TTA_info streamInfo; try { mDecoder = unique_tta_ptr(new tta::tta_decoder((TTA_io_callback *)mCallbacks.get())); mDecoder->init_get_info(&streamInfo, 0); } catch(tta::tta_exception e) { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.TrueAudio", "Error creating True Audio decoder: " << e.code()); } if(!mDecoder) { if(error) { SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” is not a valid True Audio file."), ""); SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Not a True Audio file"), ""); 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; } mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger; mFormat.mSampleRate = streamInfo.sps; mFormat.mChannelsPerFrame = streamInfo.nch; mFormat.mBitsPerChannel = streamInfo.bps; mFormat.mBytesPerPacket = ((streamInfo.bps + 7) / 8) * mFormat.mChannelsPerFrame; mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Support 4 to 32 bits per sample (True Audio may support more or less, but the documentation didn't say) switch(mFormat.mBitsPerChannel) { case 8: case 16: case 24: case 32: mFormat.mFormatFlags |= kAudioFormatFlagIsPacked; break; case 4 ... 7: case 9 ... 15: case 17 ... 23: case 25 ... 31: // Align high because Apple's AudioConverter doesn't handle low alignment mFormat.mFormatFlags |= kAudioFormatFlagIsAlignedHigh; break; default: { LOGGER_CRIT("org.sbooth.AudioEngine.Decoder.TrueAudio", "Unsupported bit depth: " << mFormat.mBitsPerChannel) if(error) { SFB::CFString description = CFCopyLocalizedString(CFSTR("The file “%@” is not a supported True Audio file."), ""); SFB::CFString failureReason = CFCopyLocalizedString(CFSTR("Bit depth not supported"), ""); SFB::CFString recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's bit depth is not supported."), ""); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } return false; } } // Set up the source format mSourceFormat.mFormatID = 'TTA '; mSourceFormat.mSampleRate = streamInfo.sps; mSourceFormat.mChannelsPerFrame = streamInfo.nch; mSourceFormat.mBitsPerChannel = streamInfo.bps; // Setup the channel layout switch(streamInfo.nch) { case 1: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; case 4: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Quadraphonic); break; } mTotalFrames = streamInfo.samples; return true; }
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; }