Files
gemigreerd-racket-audio/scrbl/play-workerthread-states.plantuml
T
2026-05-16 01:38:40 +02:00

123 lines
3.5 KiB
Plaintext

@startuml
!theme plain
hide empty description
title Placed audio player - command loop and worker detail
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundcorner 14
skinparam ArrowThickness 1.2
skinparam DefaultFontName "DejaVu Sans"
skinparam DefaultFontSize 13
skinparam state {
BackgroundColor #F8F8F8
BorderColor #555555
FontColor #222222
StartColor #555555
EndColor #555555
BackgroundColor<<blue>> #DCEEFF
BorderColor<<blue>> #3A7FC4
FontColor<<blue>> #123A63
BackgroundColor<<green>> #E3F6E3
BorderColor<<green>> #3C9D40
FontColor<<green>> #1E5C22
BackgroundColor<<orange>> #FFE8CC
BorderColor<<orange>> #D8842A
FontColor<<orange>> #7A4A12
BackgroundColor<<red>> #FFE5E5
BorderColor<<red>> #CC3333
FontColor<<red>> #7A1F1F
BackgroundColor<<gray>> #F2F2F2
BorderColor<<gray>> #888888
FontColor<<gray>> #444444
}
state "Command loop:\nreplace active worker" as A <<gray>> {
[*] -down-> CurrentWorkerActive
state "Current worker active" as CurrentWorkerActive <<orange>>
state "Interrupt requested" as InterruptRequested <<green>>
state "Waiting for worker" as WaitingForWorker <<green>>
state "Starting new worker" as StartingNewWorker <<orange>>
state "New worker active" as NewWorkerActive <<orange>>
InterruptRequested : entry / feed-interrupted := #t
InterruptRequested : entry / ao-clear-async
InterruptRequested : entry / player-state := stopped
InterruptRequested : entry / audio-stop
WaitingForWorker : do / wait until feeding-audio = #f
StartingNewWorker : entry / thread-wait
StartingNewWorker : entry / audio-open
StartingNewWorker : entry / player-state := playing
StartingNewWorker : entry / spawn worker
CurrentWorkerActive -down-> InterruptRequested : open(new)
InterruptRequested -down-> WaitingForWorker
WaitingForWorker -down-> StartingNewWorker : ready
StartingNewWorker -down-> NewWorkerActive
NewWorkerActive -down-> [*]
}
state "Worker thread lifecycle" as B <<gray>> {
[*] -down-> WorkerIdle
state "WorkerIdle" as WorkerIdle <<blue>>
state "WorkerExited" as WorkerExited <<blue>>
state "WorkerFailed" as WorkerFailed <<red>>
WorkerIdle -down-> C : open(file)\n/ audio-open\nspawn worker
state "Worker active" as C <<orange>> {
C : entry / feeding-audio := #t
C : exit / feeding-audio := #f
[*] -right-> Reading
state "Reading" as Reading <<orange>>
state "DrainingAO" as DrainingAO <<green>>
state "MarkStopped" as MarkStopped <<blue>>
state "WorkerDone" as WorkerDone <<blue>>
Reading : do / audio-read
Reading : pause #t / ao-pause #t and wait
Reading : pause #f / ao-pause #f
DrainingAO : do / wait until AO queue drains
DrainingAO : pause #t / ao-pause #t
DrainingAO : pause #f / ao-pause #f
Reading -right-> DrainingAO : audio-read returns\n[not feed-interrupted]\n/ emit audio-done
DrainingAO -right-> MarkStopped : [AO queue empty\nand file-id is current]
MarkStopped -right-> WorkerDone : / player-state := stopped
WorkerDone -right-> [*]
Reading -down-> WorkerDone : [feed-interrupted]\n/ feed-interrupted := #f
DrainingAO -down-> WorkerDone : [AO closed,\nqueue grows,\nor old file-id]
note bottom of DrainingAO
The file-id check prevents an old worker
from stopping a newly opened file.
end note
}
C -down-> WorkerExited : worker exits
C -down-> WorkerFailed : exception\n/ emit exception\nplayer-state := stopped
WorkerExited -down-> [*]
WorkerFailed -down-> [*]
}
A -[hidden]right-> B
@enduml