Files
go-mxl-player/cmd/mxl-player/playback_runtime.go
T
2026-09-01 01:22:03 +03:00

135 lines
2.5 KiB
Go

package main
import (
"log"
mxladapter "mxl-player/internal/adapter/mxl"
"mxl-player/internal/output"
"mxl-player/internal/playback"
)
type playerAudioSink interface {
playback.AudioSink
Close() error
}
var _ playerAudioSink = (*output.SDLAudioSink)(nil)
type playerPlayback struct {
Controller *playback.SessionController
Commands chan playback.SessionCommand
Video *playback.VideoBridge
Status *playback.StatusStore
Audio playerAudioSink
}
func newPlayerPlayback(
audioDevice uint32,
retry playback.RetryPolicy,
) (*playerPlayback, error) {
videoBridge := playback.NewVideoBridge()
statusStore := playback.NewStatusStore()
audioSink := output.NewSDLAudioSink(audioDevice)
observe := func(status playback.Status) {
statusStore.Observe(status)
if status.Err != nil {
log.Printf(
"%s: state=%v attempt=%d failed=%d: %v",
status.Unit,
status.State,
status.Attempt,
status.FailedAttempts,
status.Err,
)
return
}
log.Printf(
"%s: state=%v attempt=%d failed=%d",
status.Unit,
status.State,
status.Attempt,
status.FailedAttempts,
)
}
videoWorker, err := playback.NewVideoWorker(
mxladapter.VideoFactory{},
videoBridge,
retry,
mxladapter.ShouldRetry,
observe,
)
if err != nil {
_ = audioSink.Close()
return nil, err
}
videoSlot, err := playback.NewVideoSlot(videoWorker)
if err != nil {
_ = audioSink.Close()
return nil, err
}
audioWorker, err := playback.NewAudioWorker(
mxladapter.AudioFactory{},
audioSink,
retry,
mxladapter.ShouldRetry,
observe,
)
if err != nil {
_ = audioSink.Close()
return nil, err
}
audioSlot, err := playback.NewAudioSlot(audioWorker)
if err != nil {
_ = audioSink.Close()
return nil, err
}
syncWorker, err := playback.NewSyncWorker(
mxladapter.SyncFactory{},
videoBridge,
audioSink,
retry,
mxladapter.ShouldRetry,
observe,
)
if err != nil {
_ = audioSink.Close()
return nil, err
}
syncSlot, err := playback.NewSyncSlot(syncWorker)
if err != nil {
_ = audioSink.Close()
return nil, err
}
controller, err := playback.NewSessionController(
videoSlot,
audioSlot,
syncSlot,
func(video, audio playback.FeedConfig) bool {
return video.Domain == audio.Domain
},
)
if err != nil {
_ = audioSink.Close()
return nil, err
}
return &playerPlayback{
Controller: controller,
Commands: make(chan playback.SessionCommand, 32),
Video: videoBridge,
Status: statusStore,
Audio: audioSink,
}, nil
}
func (p *playerPlayback) Close() error {
return p.Audio.Close()
}