Repository navigation
0.20.0
AudioPlaybackKit 0.20.0 reads position on demand instead of pushing it every 100 ms, so a playing transport
wakes only for work and for the observers an app registers (#189,
ADR-0031).
This is a minor bump at 0.x: it changes public API (below). Decode and the PCM played are unchanged.
What changed
- Position is computed when read, as media3
Player.getCurrentPositionand AVPlayercurrentTime().
Transport.position(aTransportPosition:item,seconds) maps the output clock through a snapshot
under the transport's lock, on the caller's thread with no hop to its queue. It is nil while a
setCurrentorseekis called but not taken, and within one item and one call it never goes back.
Player.positionreads it once every call is answered and the heard item is the current one; until then
it holds the value set with the lastdiscontinuityCountchange. - Observers, named as AVPlayer's.
addPeriodicObserver(interval:using:)fires everyintervalof
output time while the clock runs (wall time at any speed).addBoundaryObserver(times:using:)fires once
when playback crosses a time in the heard item; a load or seek landing past it does not. Both are on
Transport(callbacks on its queue) andPlayer(callbacks on the main actor), and return a
TimeObserverTokenthat removes the observer oncancel()or deinit. - Events.
TransportEvent.landed(item:seconds:)is the first position of asetCurrentorseek,
once its first audio is written;seekLandedandseekAdjustedcome from it.
TransportEvent.durationChanged(item:duration:isSeekable:)is sent when the heard item's duration or
seekability changes.firstAudioRenderedis sent on.status(.playing)after a landing, or on a landing
or.crossedwhile playing. NowPlayingSessionstill writes elapsed time only on a jump, a play or pause, a rate or item change,
or drift. After a write while playing it asks the player for one periodic tick, so a play heard late is
rewritten once heard; a paused or held player wakes nothing.- Test support.
ManualPumpTimer.advancemoves the clock in 1/64 s steps, so an output's ready wake
lands as it would on a real clock.
Breaking changes
TransportEvent.position(item:seconds:duration:isSeekable:)is removed, replaced by.landedand
.durationChanged: code matching it, or an exhaustiveswitch, no longer compiles.Player.positionis computed, so SwiftUI andwithObservationTrackingno longer see it move between
discontinuities. A view that showed it by observation stops updating.NowPlayingControllablerequiresaddPeriodicObserver(interval:using:). A
ForwardingNowPlayingControllablewrapper gets it forwarded; a direct conformer must forward it to its player.
Additive: Transport.position, TransportPosition, TimeObserverToken, and both observers on Transport
and Player.
Upgrading
- A progress bar or elapsed label subscribes with
player.addPeriodicObserver(interval:using:), keeps the
token, and readsplayer.positionon each fire. - Ad and silence skips and a sleep timer at an item time use
addBoundaryObserver(times:using:)in place of
comparing each.position. - Code that read duration or seekability from
.positionreads.durationChanged, orPlayer.duration
andisSeekable.