Skip to content
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
b241b5a
Experimental mach `semaphore_t` usage
sbooth Sep 15, 2026
c79a609
Fix comment
sbooth Sep 16, 2026
268406c
Refactor msema
sbooth Sep 17, 2026
0ece850
Merge branch 'main' into msema
sbooth Sep 17, 2026
4fee845
Fix comment width
sbooth Sep 17, 2026
7bf7084
Improve `wait`
sbooth Sep 17, 2026
34a12e6
Improve `timedwait`
sbooth Sep 17, 2026
729ae62
Ensure `semaphore_timedwait` is always called
sbooth Sep 17, 2026
38a7ea7
Update includes
sbooth Sep 17, 2026
1720b77
Avoid SOIF
sbooth Sep 17, 2026
cabd4bd
Revert "Avoid SOIF"
sbooth Sep 18, 2026
8c596ba
Merge branch 'main' into msema
sbooth Sep 18, 2026
3fa86af
Remove marks
sbooth Sep 18, 2026
ca95054
constexpr where able
sbooth Sep 18, 2026
450f144
Rename helper functions
sbooth Sep 20, 2026
c87b33c
Rename parameter
sbooth Sep 20, 2026
3aa18a5
Make comments more generic
sbooth Sep 20, 2026
c64abe5
Minor updates
sbooth Sep 21, 2026
13d524b
Improve seek responsiveness
sbooth Sep 21, 2026
9f5f6bf
Remove `CXXDispatchSemaphore` dependency
sbooth Sep 21, 2026
862b763
Add `detail::timespec_zero`
sbooth Sep 21, 2026
0e5c835
Use more appropriate constants
sbooth Sep 21, 2026
8de0bac
throw `system_error` on ctor fail
sbooth Sep 21, 2026
4a4c169
Add mach error category
sbooth Sep 21, 2026
ed5e1e8
Add `timedwait_result`
sbooth Sep 21, 2026
cb0449d
Consistent scoping
sbooth Sep 21, 2026
15a49a1
Format
sbooth Sep 21, 2026
3382863
Merge branch 'main' into msema
sbooth Nov 1, 2026
dfcb670
Merge branch 'main' into msema
sbooth Nov 1, 2026
bf2f036
Merge branch 'main' into msema
sbooth Nov 2, 2026
68a1296
Merge branch 'main' into msema
sbooth Nov 2, 2026
4aa34b8
Reformat
sbooth Nov 2, 2026
f11ea9e
Use existing host time utilities
sbooth Nov 2, 2026
4b5b31e
Remove newline
sbooth Nov 2, 2026
27d6530
Simplify marks
sbooth Nov 2, 2026
dd76694
Merge branch 'main' into msema
sbooth Nov 2, 2026
8240f25
Signal the event semaphore after enqueuing a pause
sbooth Nov 3, 2026
03b8f8e
Remove cast
sbooth Nov 3, 2026
ccd0873
Add `timedwait(uint64_t nanoseconds)`
sbooth Nov 3, 2026
f4a5421
Use `mach_task_self()` directly
sbooth Nov 3, 2026
b1b9ad2
Use `host_time::current()`
sbooth Nov 3, 2026
a226e7e
Merge branch 'main' into msema
sbooth Nov 3, 2026
a47c7a8
Merge branch 'main' into msema
sbooth Nov 3, 2026
1ada712
Coalesce event signals
sbooth Nov 4, 2026
c7decc8
Increase event processing timeout
sbooth Nov 4, 2026
fc499cf
Only log event processing timeout in debug builds
sbooth Nov 4, 2026
7c6136e
Add constant for timeout
sbooth Nov 4, 2026
870f96d
Add debug diagnostic logging for missed decoding signals
sbooth Nov 4, 2026
1e9a0e1
Add member function prototype
sbooth Nov 4, 2026
8530d05
Use `std::chrono` for timeout specification
sbooth Nov 4, 2026
d9358d4
Refactor
sbooth Nov 4, 2026
2ac2c94
Refactor timeout
sbooth Nov 4, 2026
fea6074
Merge branch 'main' into msema
sbooth Nov 4, 2026
d6f332d
Only signal the event thread when events were enqueued
sbooth Nov 5, 2026
107bc80
Rename `decodingWorkPending`
sbooth Nov 5, 2026
2142b5d
Reword log message
sbooth Nov 5, 2026
8b8ef84
Reformat
sbooth Nov 5, 2026
e9ece8f
Merge branch 'main' into msema
sbooth Nov 5, 2026
441f1f6
Merge branch 'main' into msema
sbooth Nov 5, 2026
804683a
Reformat
sbooth Nov 5, 2026
58c8620
Merge branch 'main' into msema
sbooth Nov 5, 2026
d7f9e7f
Use new flag name
sbooth Nov 6, 2026
0315657
Merge branch 'main' into msema
sbooth Nov 6, 2026
8bfec9c
Merge branch 'main' into msema
sbooth Nov 7, 2026
19c1c23
Update `DEBUG` conditionals
sbooth Nov 7, 2026
90f2a16
Merge branch 'main' into msema
sbooth Nov 7, 2026
db624f3
Update for changes to main
sbooth Nov 7, 2026
1a5f932
Rework `timedwait()`
sbooth Nov 9, 2026
6ac6d01
Change return type of `timedwait()` to `bool`
sbooth Nov 9, 2026
323dc4e
Rename `timedwait()`
sbooth Nov 9, 2026
8bffc84
Rename `wait_time` and `signal_all`
sbooth Nov 9, 2026
84f64d5
Restructure `wait()`
sbooth Nov 10, 2026
085ccd0
Add `[[unlikely]]`
sbooth Nov 10, 2026
d2819cb
Remove unused functions
sbooth Nov 10, 2026
6bdd647
Merge branch 'main' into msema
sbooth Nov 10, 2026
9654fee
Add code voice to comments
sbooth Nov 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions Sources/CSFBAudioEngine/Player/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#import <atomic>
#import <cassert>
#import <chrono>
#import <deque>
#import <memory>
#import <mutex>
Expand Down Expand Up @@ -148,13 +149,16 @@ class AudioPlayer final {

/// Thread used for decoding
std::jthread decodingThread_;
/// Dispatch semaphore used for communication with the decoding thread
dsema::Semaphore decodingSemaphore_{0};
/// Semaphore used for communication with the decoding thread
msema::Semaphore decodingSemaphore_{0};

/// Thread used for event processing
std::jthread eventThread_;
/// Dispatch semaphore used for communication with the event processing thread
dsema::Semaphore eventSemaphore_{0};
/// Semaphore used for communication with the event processing thread
msema::Semaphore eventSemaphore_{0};
Comment thread
sbooth marked this conversation as resolved.
Resolved
/// Whether `eventSemaphore_` has been signaled since the event processing thread last began draining events
std::atomic_bool eventSignaled_{false};
static_assert(std::atomic_bool::is_always_lock_free, "Lock-free std::atomic_bool required");

/// Message queue communicating events to the event processing thread
mpsc::MessageQueue<256, 32> events_;
Expand Down Expand Up @@ -424,7 +428,13 @@ class AudioPlayer final {
bool decodeIntoRingBuffer(DecoderState *_Nonnull &decoderState, AVAudioPCMBuffer *buffer) noexcept;

/// Returns the appropriate decoding semaphore timeout
int64_t decodingTimeout(DecoderState *_Nullable decoderState) const noexcept;
std::chrono::nanoseconds decodingTimeout(DecoderState *_Nullable decoderState) const noexcept;

#if DEBUG
/// Returns `true` if the decoding thread has a decoder to process and should not be idle
/// - note: Used only to detect missed signals when a wait with no decoder to process times out
bool shouldBeProcessingDecoders() const noexcept;
#endif /* DEBUG */

// MARK: - Rendering

Expand All @@ -433,10 +443,12 @@ class AudioPlayer final {
AudioBufferList &outputData) noexcept;

/// Enqueues frames rendered event(s) for rendered audio
void enqueueFramesRenderedEvents(uint32_t framesRead, const AudioTimeStamp &timestamp) noexcept;
/// - returns: `true` if an event was enqueued
[[nodiscard]] bool enqueueFramesRenderedEvents(uint32_t framesRead, const AudioTimeStamp &timestamp) noexcept;

/// Enqueues an empty frames rendered event if an empty decoded chunk descriptor is present
void enqueueEmptyFramesRenderedEvent(const AudioTimeStamp &timestamp) noexcept;
/// - returns: `true` if an event was enqueued
[[nodiscard]] bool enqueueEmptyFramesRenderedEvent(const AudioTimeStamp &timestamp) noexcept;

/// The current rendering chunk descriptor
std::optional<detail::RenderingChunkDescriptor> renderingChunk_{};
Expand Down Expand Up @@ -521,6 +533,9 @@ class AudioPlayer final {
void handleRenderingWillCompleteEvent(Decoder _Nonnull decoder, uint64_t hostTime,
uint64_t outputGeneration) noexcept;

/// Signals the event semaphore if required
void signalEventSemaphore() noexcept;

// MARK: - Transport Snapshots

/// Publishes a playback snapshot.
Expand Down Expand Up @@ -640,6 +655,12 @@ inline AVAudioMixerNode *_Nonnull AudioPlayer::mainMixerNode() const noexcept {

inline AVAudioOutputNode *_Nonnull AudioPlayer::outputNode() const noexcept { return engine_.outputNode; }

inline void AudioPlayer::signalEventSemaphore() noexcept {
if (!eventSignaled_.exchange(true, std::memory_order_acq_rel)) {
eventSemaphore_.signal();
}
}

// MARK: Transport Snapshot

inline bool detail::TransportSnapshot::getPlaybackPositionAndTime(SFBPlaybackPosition *position,
Expand Down
Loading
Loading