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 MediaStats *playback.MediaStatsStore Audio playerAudioSink } func newPlayerPlayback( audioDevice uint32, retry playback.RetryPolicy, ) (*playerPlayback, error) { videoBridge := playback.NewVideoBridge() statusStore := playback.NewStatusStore() mediaStats := playback.NewMediaStatsStore() audioSink := output.NewSDLAudioSink(audioDevice) videoSink := playback.VideoStatsSink{Stats: mediaStats, Sink: videoBridge} observedAudioSink := playback.AudioStatsSink{Stats: mediaStats, Sink: audioSink} 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{}, videoSink, 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{}, observedAudioSink, 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{}, videoSink, observedAudioSink, 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, MediaStats: mediaStats, Audio: audioSink, }, nil } func (p *playerPlayback) Close() error { return p.Audio.Close() }