Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions Sources/CSFBAudioEngine/Player/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,9 @@ class AudioPlayer final {
bool configureForDecoder(DecoderState *_Nullable &decoderState, AVAudioPCMBuffer *_Nullable __strong &buffer,
bool &formatMismatch) noexcept;

/// Resets the render state and clears `Flags::audioStale` if the engine is not running
void resetRenderStateIfEngineNotRunning() noexcept;

/// Decodes audio from `decoderState` into the ring buffer
bool decodeIntoRingBuffer(DecoderState *decoderState, AVAudioPCMBuffer *buffer) noexcept;

Expand Down
37 changes: 33 additions & 4 deletions Sources/CSFBAudioEngine/Player/AudioPlayer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,8 @@ Flags clearFlags(Flags flags, std::memory_order order = std::memory_order_acq_re
clearDecoderQueue();
cancelActiveDecoders();

setFlags(Flags::audioStale);

if (didStopEngine) {
if (__strong id<SFBAudioPlayerDelegate> delegate = player_.delegate;
delegate != nil && [delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
Expand Down Expand Up @@ -838,8 +840,11 @@ Flags clearFlags(Flags flags, std::memory_order order = std::memory_order_acq_re
std::lock_guard lock{engineMutex_};
[engine_ reset];
}

clearDecoderQueue();
cancelActiveDecoders();

setFlags(Flags::audioStale);
}

// MARK: - Player State
Expand Down Expand Up @@ -1142,9 +1147,13 @@ Flags clearFlags(Flags flags, std::memory_order order = std::memory_order_acq_re
continue;
}

// Decode and write chunks to the ring buffer
if (decoderState != nullptr && !decodeIntoRingBuffer(decoderState, buffer)) {
continue;
if (decoderState != nullptr) {
// Reset the render state
resetRenderStateIfEngineNotRunning();
// Decode and write chunks to the ring buffer
if (!decodeIntoRingBuffer(decoderState, buffer)) {
continue;
}
}

// Wait for an event signal; ring buffer space availability is polled using the timeout
Expand Down Expand Up @@ -1486,14 +1495,34 @@ Flags clearFlags(Flags flags, std::memory_order order = std::memory_order_acq_re
return true;
}

void sfb::AudioPlayer::resetRenderStateIfEngineNotRunning() noexcept {
if (const auto flags = loadFlags(); bits::is_clear(flags, Flags::audioStale)) [[likely]] {
return;
}

std::lock_guard lock{engineMutex_};

// Only perform non-thread safe operations if the engine is not running
if (engine_.isRunning) {
return;
}

// Reset the render state
audioBuffer_.discardAll();
audioMetadata_.discardAll();
renderingChunk_ = {};

clearFlags(Flags::audioStale);
}

bool sfb::AudioPlayer::decodeIntoRingBuffer(DecoderState *decoderState, AVAudioPCMBuffer *buffer) noexcept {
#if DEBUG
assert(decoderState != nullptr);
assert(buffer != nil);
#endif /* DEBUG */

const auto flags = loadFlags();
if (bits::is_set(flags, Flags::audioStale)) {
if (bits::is_set(flags, Flags::audioStale)) [[unlikely]] {
return true;
}

Expand Down