Releases: sbooth/SFBAudioEngine
Version 0.12.0
SFBAudioEngine Version 0.12.0 Release Notes
Published: February 15, 2026
🚨 Breaking API Changes
This release contains three breaking API changes that require code updates when migrating from version 0.11.0.
1. Delegate Method: audioPlayer:nowPlayingChanged: (#569)
The previouslyPlaying parameter has been removed from the delegate method signature.
Before (0.11.0 and earlier):
- (void)audioPlayer:(SFBAudioPlayer *)audioPlayer
nowPlayingChanged:(SFBAudioPlayerNode *)nowPlaying
previouslyPlaying:(SFBAudioPlayerNode *)previouslyPlayingAfter (0.12.0):
- (void)audioPlayer:(SFBAudioPlayer *)audioPlayer
nowPlayingChanged:(SFBAudioPlayerNode *)nowPlayingMigration Guide: Remove the previouslyPlaying: parameter from your delegate method implementation. If you need to track the previously playing item, maintain this state in your delegate implementation.
2. Delegate Method: Audio Engine Configuration Change (#692)
The audio engine configuration change notification has been renamed and now includes a userInfo dictionary parameter.
Before (0.11.0 and earlier):
- (void)audioPlayerAVAudioEngineConfigurationChange:(SFBAudioPlayer *)audioPlayerAfter (0.12.0):
- (void)audioPlayer:(SFBAudioPlayer *)audioPlayer
audioEngineConfigurationChange:(NSDictionary *)userInfoMigration Guide:
- Update the method name to include the
audioPlayer:prefix - Add the
userInfo:parameter to access configuration change details - Consult the dictionary for specific information about the configuration change
3. Class Rename: OutputSource → OutputTarget (#855)
All references to OutputSource have been renamed to OutputTarget for better semantic clarity.
Migration Guide: Perform a find-and-replace in your codebase:
SFBOutputSource→SFBOutputTargetOutputSource→OutputTarget- Any related class, method, or variable names
✨ Enhancements
Audio Processing
- ITU BS.1770 Replay Gain: Implemented revised replay gain calculation using the ITU BS.1770 standard for improved loudness normalization (#842)
- FLAC Channel Layout Improvements: Channel layouts for FLAC files now match Core Audio conventions (#848)
- WAVEFORMATEXTENSIBLE Support: Added support for
WAVEFORMATEXTENSIBLE_CHANNEL_MASKfor better Windows audio format compatibility (#849)
🐛 Bug Fixes
- Buffer Offset Calculation: Fixed an error in buffer offset calculation that could affect audio encoding (#805)
🔧 Code Quality & Maintenance
Formatting & Style
- Comprehensive Code Formatting: Applied clang-format across the entire codebase for consistent code style (#794)
- Clang-tidy Improvements: Applied multiple clang-tidy readability improvements (#802, #804, #807)
- Modern C++ Practices: Replaced
BOOLwithbool,NULLwithnullptr, and improved pointer checks (#810, #811, #821)
Licensing
- SPDX File Headers: Added SPDX file headers for better license compliance (#841)
- MIT License: Updated to use MIT license text from REUSE (#846)
Dependencies
- Dependency Updates: Updated and refined external dependencies (#833, #866)
- Removed CXXCoreAudio Dependency: Replaced with internal implementations (#836)
- Removed CXXAudioToolbox Dependency: (#835)
- Added CXXDispatchSemaphore: New dependency for synchronization primitives (#838)
CI/CD
- cpp-linter Workflow: Added automated C++ linting to continuous integration (#869, #870)
- clang-format Checks: Added automated formatting verification (#798)
📦 Full Changelog
This release includes 82 pull requests focused on code quality, modernization, and the breaking API changes listed above. Notable internal improvements include extensive refactoring for better maintainability and standards compliance.
📥 Installation
Swift Package Manager
dependencies: [
.package(url: "https://github.com/sbooth/SFBAudioEngine", from: "0.12.0")
]🙏 Credits
All changes in this release were authored by @sbooth.
Need Help? If you encounter any issues migrating to version 0.12.0, please open an issue on GitHub.
Version 0.11.0
SFBAudioEngine Version 0.11.0 Release Notes
Released: January 19, 2026
🚨 Breaking API Changes
Class Rename
Rename LoopableRegionDecoder to AudioRegionDecoder (#765)
The class LoopableRegionDecoder has been renamed to AudioRegionDecoder and improved.
Migration: Update all references from LoopableRegionDecoder to AudioRegionDecoder in your codebase.
📋 What's Changed
🎯 Playback Improvements
- Fixed a race condition leading to erroneous now playing changes (#702)
- Simplified playback state calculation (#701)
- Improved accounting of frames rendered from canceled decoders (#725)
- Ensure playback state transitions are sequenced properly (#782)
- Update now playing when decoding starts and not playing (#734)
🔧 Decoder & Encoder Enhancements
- Enhanced FLAC decoder (#771)
- Fix bug in FLAC seeking (#766)
- Improve and rename
LoopableRegionDecodertoAudioRegionDecoder(#765)⚠️ Breaking Change - Add
decoderread-only property (#768) - Cancel decoder when a decoding error occurs (#772)
- Cancel decoding when a non-recoverable seek error occurs (#731)
- Clean up Shorten decoder (#730)
- Catch C++ exceptions in
-openReturningError:(#767)
🐛 Bug Fixes
- Prevent UAF in rendering started and complete notifications (#781)
- Don't leave
decoderStatenull after processing cancelations (#710) - Ensure
NSErrorobjects are created on seek failure (#732) - Return more appropriate error codes for decoding errors (#733)
- Log messages about mid-stream format changes as errors (#775)
✨ New Delegate Methods
- Add
-audioPlayer:decodingAborted:error:framesRendered:delegate method (#779) - Add
audioPlayer:audioSessionInterruption:delegate method (#787)
⚠️ Error Handling Improvements
- Consolidate error domains for decoding and improve error messages (#735)
- Update audio player errors (#741)
- Update error domains/codes and Swift names (#743)
- Use
SFBErrorWithLocalizedDescriptionthroughout the codebase (#745, #747, #748, #749, #751, #753, #754) - Improve DSD to PCM and DoP error messages (#764)
- Improve
DSDDecodererror messages (#755)
🏗️ Architecture & Internal Improvements
- Replace
SeekForwardandSeekBackwardwithSeekInTime(#718) - Remove
EventHeaderstruct and simplify event processing (#720) - Remove
Flags::formatMismatch(#726) - Move
AudioPlayerandDecoderStatemethod implementations (#727) - Add
fetch_updategeneric atomic RMW function (#723, #724) - Ensure the processing graph is reconfigured before decoding starts (#713)
- Refactor enqueue logic (#708)
- Ensure all cancelations are processed in sequence (#707)
- Ensure all ensuing decoders suspended following seek (#709)
- Don't access
audioRingBuffer_in event processing thread (#785) - Rework host time utilities (#789)
💅 Code Quality & Formatting
- Adopt a new C++ coding style (#790)
- Standardize
elseformatting (#773) - Update documentation comments (#739)
- Add nullability specifiers (#752)
- Give all ivars in internal headers package visibility (#759)
- Reformat
ReplayGainAnalyzer(#762) - Update year to 2026 (#721)
📦 Dependency Updates
- Update
CXXRingBufferandCXXCoreAudio(#717) - Update dependencies and tighten version requirements for pre-1.0 packages (#792)
- Add header to Package.swift (#728)
🔊 Audio Engine Improvements
- Increase event buffer sizes (#703)
- Increase log level for ring buffer write failures (#704)
- Use a mask in
Renderto check not playing or muted (#705) - Remove
unmuteAfterDequeueflag (#716) - Clear
Flags::formatMismatchwhen decoding resumed (#712)
🎵 Audio Session Handling
- Improvements to audio session interruption handling (#787)
- Rename
handleAudioSessionInterruption(#791)
🛠️ Miscellaneous
- Only use simd packed vectors when dealing with memory (#776)
- Use
reinterpret_cast(#777) - Use
<<=operator (#778) - Use
auto *where appropriate (#719) - Use kHz for kilohertz (#770)
📝 Full Changelog
Full Changelog: 0.10.0...0.11.0
This release includes 94 pull requests.
📥 Installation
Swift Package Manager
dependencies: [
.package(url: "https://github.com/sbooth/SFBAudioEngine", from: "0.11.0")
]🙏 Credits
All changes in this release were authored by @sbooth.
Need Help? If you encounter any issues migrating to version 0.11.0, please open an issue on GitHub.
Version 0.10.0
What's Changed
- Slight simplification to
Renderby @sbooth in #668 - Improvements to
SubmitDecodingErrorEventby @sbooth in #669 - Integrate with new
AudioRingBufferread behavior by @sbooth in #670 - Remove
Flags::ringBufferNeedsResetby @sbooth in #671 - Simplify ring buffer reset logic by @sbooth in #672
- Use a longer event semaphore timeout when idle by @sbooth in #676
- Ensure
erroris set on short reads by @sbooth in #677 - Use
uint8_tfor pointer arithmetic with known types by @sbooth in #678 - Use
unsigned charinstead ofuint8_tby @sbooth in #679 - Return an error on decoding failure by @sbooth in #680
- Fixes to
SubmitDecodingErrorEvent()by @sbooth in #682 - Ensure error object is created on failure by @sbooth in #683
- Add
-closeReturningError:toAudioConverterby @sbooth in #684 - Don't read past DSF
datachunk when decoding by @sbooth in #685 - Add
-descriptionto decoder wrappers by @sbooth in #686 - Fix warning about implicit conversion by @sbooth in #687
- Use
EINVALinstead ofparamErrby @sbooth in #688 - Replace
SFBAudioPlayerNodewithAVAudioSourceNodeby @sbooth in #664 - Replace
-withEngine:with-modifyProcessingGraph:by @sbooth in #689 - Add an
assertafter-audioPlayer:reconfigureProcessingGraph:withFormat:by @sbooth in #690 - Improve logging in
HandleAudioEngineConfigurationChangeby @sbooth in #691 - Add
boolreturn toPauseandResumeby @sbooth in #694 - Improvements to audio session interruption handling by @sbooth in #693
- Update to C++17
ifsyntax by @sbooth in #695 - Additional error checking in DSF and DFF parsers by @sbooth in #696
- Update
CXXCoreAudioandCXXRingBufferby @sbooth in #698
Full Changelog: 0.9.1...0.10.0
Version 0.9.1
Version 0.9.0
What's Changed
- Mark
-initas designated initializer inSFBMutableDataOutputSourceby @sbooth in #647 - Increase
CXXTagLibminimum version to 2.1.1 by @sbooth in #648 - Ensure input source is open before sending
-supportsSeekingby @sbooth in #649 - Avoid logging a null decoder by @sbooth in #652
- Refactor processing graph configuration by @sbooth in #654
- Check if engine is running before sending
startAndReturnError:by @sbooth in #655 - Add a lock protecting enqueues and engine configuration changes by @sbooth in #653
- Correct name of the player node getter method by @sbooth in #657
- Additional comments by @sbooth in #658
- Rename decoder managment methods by @sbooth in #659
- Remove explicitly deleted move constructor and assignment operator by @sbooth in #660
- Reset decoder state in
-openReturningError:and-closeReturningError:by @sbooth in #578 - Reset encoder state in
-openReturningError:and-closeReturningError:by @sbooth in #661 - Add a lock protecting the audio player node by @sbooth in #640
- Add
-to source code marks by @sbooth in #662
Full Changelog: 0.8.0...0.9.0
Version 0.8.0
What's Changed
- Fix VLA folding warnings by @sbooth in #593
- Avoid opening file handle unnecessarily by @sbooth in #594
- Mark
SFBInputSource.newandinitas unavailable by @sbooth in #596 - Mark
SFBOutputSource.newandinitas unavailable by @sbooth in #597 - Reconfigure the audio processing graph during enqueue if needed by @sbooth in #600
- Avoid unnecessary calls to
AVAudioChannelLayoutsAreEquivalentby @sbooth in #601 - Add permissions to workflow by @sbooth in #603
- Replace
std::threadwithstd::jthreadby @sbooth in #602 - Replace
SFB::DispatchSemaphorewithdispatch_semaphore_tby @sbooth in #604 - Add
noexceptto~AudioPlayerNode()by @sbooth in #605 - Small improvements to host time functions by @sbooth in #606
- Use scoped enumerations for flags by @sbooth in #607
- CTAD for
std::lock_guardby @sbooth in #610 - Call
request_stopandjoindirectly by @sbooth in #611 - Handle exceptions thrown by
jthread::joinby @sbooth in #612 - Refactor
SFBAudioPlayerC++ implementation by @sbooth in #608 - Add DEBUG guard by @sbooth in #614
- Add getter to
SFBAudioPlayerforaudioPlayerNodeproperty by @sbooth in #615 - Inline simple functions by @sbooth in #616
- Remove audio engine isolation queue by @sbooth in #618
- Increase log level to
faultif mpg123 fails to initialize by @sbooth in #624 - Refactor package dependencies by @sbooth in #621
- Skip junk in MP3 files when performing content type detection by @sbooth in #626
- Update to Monkey's Audio SDK version 11.82 by @sbooth in #627
- Bump actions/checkout from 5 to 6 by @dependabot[bot] in #628
- Add explicit memory ordering by @sbooth in #629
- Throw
bad_allocinstead ofsystem_errorby @sbooth in #631 - Rename scoped enumeration enumerators by @sbooth in #632
- Remove
mprefix from data members by @sbooth in #633 - Reformat
elseandcatchby @sbooth in #634 - Refactor audio engine setup and player node creation by @sbooth in #635
- Remove unnecessary assertion by @sbooth in #636
- Update data member name by @sbooth in #637
- Update audio player log name by @sbooth in #638
- Simplify code since
playerNode_will not benilby @sbooth in #639 - Update CXXAudioToolbox to version 0.1.1 by @sbooth in #641
- Update mpg123 to version 1.33.3 by @sbooth in #642
- Update ogg to version 1.3.6 by @sbooth in #643
- Use
mpg123_reader64for large file support by @sbooth in #644 - Capture
wvecby reference in lambda by @sbooth in #645 - Use renamed
AudioRingBuffermethods by @sbooth in #646
Full Changelog: 0.7.2...0.8.0
Version 0.7.2
Summary of changes:
Metadata
- Shorten properties and metadata now provided by TagLib
Encoding
- Fixed a bug in the Monkey's Audio encoder
- Fixed a bug in the libsndfile encoder
Miscellaneous
- Renamed the
_implpointer inSFBAudioPlayerNodeto avoid conflict withAVAudioNode - Updated versions of FLAC, Monkey's Audio, WavPack, mpg123, and TagLib dependencies
Version 0.7.1
Summary of changes:
Metadata
- Handle C++ exceptions when reading/writing metadata
Version 0.7.0
Summary of changes:
Playback
SFBAudioPlayerNodechanges:
- Added ability to seek backward in a rendering decoder after decoding has finished
- Fixed race condition accessing active decoders
- Decoding now uses a dedicated thread
SFBAudioPlayerchanges:
- Changed
-audioPlayer:nowPlayingChanged:previouslyPlaying:
Miscellaneous
- Minor refactoring of
SFBPlaybackPositionandSFBPlaybackTime - Small changes to restore compatibility with older Swift and Xcode versions
Version 0.6.0
Summary of changes:
Playback
- Improved continuity of playback state when switching audio formats
- Improved handling of multichannel audio channel mapping
SFBAudioPlayerNodechanges:
- Added
-audioPlayerNode:renderingDecoder:willChangeToDecoder:atHostTime: - Removed
-audioPlayerNode:audioWillEndAtHostTime: - Changed
-audioPlayerNode:decoderCanceled:framesRendered: - Removed
-delegateQueue
SFBAudioPlayerchanges:
- Added
-audioPlayer:reconfigureProcessingGraph:withFormat: - Removed
audioPlayer:audioWillEndAtHostTime: - Changed
-audioPlayer:nowPlayingChanged: - Changed
-audioPlayer:playbackStateChanged: - Changed
-audioPlayer:decoderCanceled:framesRendered:
- Unified playback position and time structures across Objective-C and Swift
Encoding
- FLAC and Ogg FLAC encoders now work correctly for bit depths less than 32
- FLAC compression level 0 is now supported
Conversion
- Improved handling of conversion errors