Skip to content

Commit

Permalink
Add -cancelCurrentDecoder (#556)
Browse files Browse the repository at this point in the history
Also adds `-cancelActiveDecoders`
  • Loading branch information
sbooth authored Jan 21, 2025
1 parent 37ed372 commit e18876e
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 10 deletions.
4 changes: 2 additions & 2 deletions Sources/CSFBAudioEngine/Player/AudioPlayerNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ struct AudioPlayerNode final {

public:
id<SFBPCMDecoding> _Nullable CurrentDecoder() const noexcept;
void CancelActiveDecoders() noexcept;
void CancelActiveDecoders(bool cancelAllActive) noexcept;

void ClearQueue() noexcept
{
Expand All @@ -205,7 +205,7 @@ struct AudioPlayerNode final {
void Reset() noexcept
{
ClearQueue();
CancelActiveDecoders();
CancelActiveDecoders(true);
}

private:
Expand Down
17 changes: 10 additions & 7 deletions Sources/CSFBAudioEngine/Player/AudioPlayerNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -401,19 +401,20 @@ bool PerformSeekIfRequired() noexcept
throw std::runtime_error("dispatch_queue_create_with_target failed");
}

// Create the dispatch group used to track event processing initiated from the decoding queue
mEventProcessingGroup = dispatch_group_create();
if(!mEventProcessingGroup) {
os_log_error(sLog, "Unable to create event processing dispatch group: dispatch_group_create failed");
throw std::runtime_error("dispatch_group_create failed");
}

// Create the dispatch source used to trigger event processing from the render block
mEventProcessingSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, mEventProcessingQueue);
if(!mEventProcessingSource) {
os_log_error(sLog, "Unable to create event processing dispatch source: dispatch_source_create failed");
throw std::runtime_error("dispatch_source_create failed");
}

mEventProcessingGroup = dispatch_group_create();
if(!mEventProcessingGroup) {
os_log_error(sLog, "Unable to create event processing dispatch group: dispatch_group_create failed");
throw std::runtime_error("dispatch_group_create failed");
}

dispatch_set_context(mEventProcessingSource, this);
dispatch_source_set_event_handler_f(mEventProcessingSource, process_pending_events_f);

Expand Down Expand Up @@ -698,7 +699,7 @@ bool PerformSeekIfRequired() noexcept
return decoderState ? decoderState->mDecoder : nil;
}

void SFB::AudioPlayerNode::CancelActiveDecoders() noexcept
void SFB::AudioPlayerNode::CancelActiveDecoders(bool cancelAllActive) noexcept
{
auto cancelDecoder = [&](DecoderState * _Nonnull decoderState) {
// If the decoder has already finished decoding, perform the cancelation manually
Expand All @@ -722,6 +723,8 @@ bool PerformSeekIfRequired() noexcept
// Cancel all active decoders in sequence
if(auto decoderState = GetActiveDecoderStateWithSmallestSequenceNumber(); decoderState) {
cancelDecoder(decoderState);
if(!cancelAllActive)
return;
decoderState = GetActiveDecoderStateFollowingSequenceNumber(decoderState->mSequenceNumber);
while(decoderState) {
cancelDecoder(decoderState);
Expand Down
10 changes: 10 additions & 0 deletions Sources/CSFBAudioEngine/Player/SFBAudioPlayerNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ - (BOOL)enqueueDecoder:(id <SFBPCMDecoding>)decoder error:(NSError **)error
return _impl->CurrentDecoder();
}

- (void)cancelCurrentDecoder
{
_impl->CancelActiveDecoders(false);
}

- (void)cancelActiveDecoders
{
_impl->CancelActiveDecoders(true);
}

- (void)clearQueue
{
_impl->ClearQueue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ NS_SWIFT_NAME(AudioPlayerNode) @interface SFBAudioPlayerNode : AVAudioSourceNode
/// Returns the decoder supplying the earliest audio frame for the next render cycle or `nil` if none
/// - warning: Do not change any properties of the returned object
@property (nonatomic, nullable, readonly) id <SFBPCMDecoding> currentDecoder;
/// Cancels the current decoder
/// - note: It is normally recommended to use `-cancelActiveDecoders` instead
- (void)cancelCurrentDecoder;
/// Cancels all active decoders
///
/// Although there is normally only one active decoder at a time, two are active during transition periods.
/// A transition period occurs when decoder *A* has completed decoding but not yet completed rendering
/// and decoder *B* has started decoding but not yet started rendering.
- (void)cancelActiveDecoders;

/// Empties the decoder queue
- (void)clearQueue;
Expand All @@ -156,7 +165,7 @@ NS_SWIFT_NAME(AudioPlayerNode) @interface SFBAudioPlayerNode : AVAudioSourceNode
- (void)play;
/// Pauses audio from the current decoder and pushes silence
- (void)pause;
/// Cancels the current decoder, clears any queued decoders, and pushes silence
/// Cancels all active decoders, clears any queued decoders, and pushes silence
- (void)stop;
/// Toggles the playback state
- (void)togglePlayPause;
Expand Down

0 comments on commit e18876e

Please sign in to comment.