better state reporting

This commit is contained in:
2026-05-19 14:30:57 +02:00
parent ef68672203
commit 2daaafb229
3 changed files with 56 additions and 9 deletions
+1 -1
View File
@@ -392,7 +392,7 @@
(let ((m-id (hash-ref h 'at-music-id)))
(unless (and (null? force) (or (eq? m-id #f) (= m-id 0)))
(cb (list 'state h))))
(cb (list 'state (list h player-state)))))
)
)
+5 -4
View File
@@ -130,7 +130,7 @@
(cmd-put (cons cmd args)) (ret-get))))
(let* ((handle #f)
(cb-state* (λ (st) (cb-state handle st)))
(cb-state* (λ (st st-hash) (cb-state handle st st-hash)))
(cb-eof* (λ () (cb-eof-stream handle))))
(set! handle (make-audio-play #t
cb-state* cb-eof*
@@ -144,10 +144,11 @@
(let loop ()
(if (audio-play-valid? handle)
(let ((e (evt-get 500)))
(cond ((eq? e #f) (loop))
(cond ((eq? e #f) (void))
((is-event? e 'state)
(set-audio-play-state! handle (evt-data e))
(cb-state* (evt-data e)))
(let ((data (evt-data e)))
(set-audio-play-state! handle (car data))
(cb-state* (cadr data) (car data))))
((is-event? e 'audio-done) (cb-eof*))
((is-event? e 'exception)
(err-sound "audio-player: exception event: ~a" e))
+50 -4
View File
@@ -36,11 +36,54 @@ all other procedures in this module.
The @racket[cb-state] callback is called as:
@racketblock[
(cb-state player state-hash)]
(cb-state player current-player-state state-hash)]
where @racket[player] is the player handle and @racket[state-hash] is the most
recent state snapshot received from the worker side. The callback is called
from the event thread created by @racket[make-audio-player].
where @racket[player] is the player handle,
@racket[current-player-state] is the logical player state reported by the
worker, and @racket[state-hash] is the most recent state snapshot received from
the worker side. The callback is called from the event thread created by
@racket[make-audio-player].
The worker-side player state is one of the following symbols:
@itemlist[
#:style 'compact
@item{@racket['stopped] -- no stream is currently playing. This is the
initial state of the placed player. The player also enters this state after
@racket[audio-stop!] or after the decoder has reached the end of the stream
and the libao output queue has drained.}
@item{@racket['playing] -- a stream is active. The decoder may still be
reading from the input file, or the decoder may already have finished while
libao is still playing queued PCM samples.}
@item{@racket['paused] -- playback is paused. The current stream is retained
and the libao output side is paused. Resuming playback moves the player back
to @racket['playing].}
@item{@racket['quit] -- the placed player has been asked to terminate. This
is the terminal state of the worker.}
]
The wrapper around the placed player may also report these states through
@racket[audio-state]:
@itemlist[
#:style 'compact
@item{@racket['initialized] -- the audio handle has been created, but no
worker-side state snapshot has been received yet.}
@item{@racket['invalid] -- the audio handle is no longer valid. This happens
after @racket[audio-quit!] or when the underlying place or thread has stopped.}
]
The @racket[state-hash] contains the detailed playback state reported by the
worker. It includes values such as the current playback position, stream
duration, buffer status, music id, and libao handle validity. Code that only
needs the logical playback state should use @racket[current-player-state]
instead of extracting it from the hash.
The @racket[cb-eof-stream] callback is called as:
@@ -52,6 +95,8 @@ that the decoder has finished queueing the stream. The audio device may still
have buffered samples to play, and the logical player state may move to
@racket['stopped] slightly later when the output queue has drained.
End-of-stream is not represented as a separate player state.
When @racket[use-place] is true, @racket[make-audio-player] starts
@racket[placed-player] with @racket[dynamic-place] and communicates with it
through place channels. When @racket[use-place] is false, the same command loop
@@ -65,6 +110,7 @@ other active threads in the main VM. Those delays can otherwise be heard as
clicks, gaps, or stuttering playback. Thread mode is useful for debugging the
protocol and callbacks, but it is not the preferred mode for robust playback.}
@defproc[(audio-play? [v any/c]) boolean?]{
Returns @racket[#t] when @racket[v] is a currently valid audio player handle.