Update audio playback to oto v3 API and fix imports
This commit is contained in:
parent
602b5854cc
commit
9e39aee5c8
31
main.go
31
main.go
|
|
@ -8,7 +8,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
|
@ -7166,9 +7168,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
// Update options and color map for all registered quality widgets
|
// Update options and color map for all registered quality widgets
|
||||||
qualityColorMap := ui.BuildQualityColorMap(newOptions)
|
qualityColorMap := ui.BuildQualityColorMap(newOptions)
|
||||||
for _, w := range uiState.qualityWidgets {
|
for _, w := range uiState.qualityWidgets {
|
||||||
w.Options = newOptions
|
w.UpdateOptions(newOptions, qualityColorMap)
|
||||||
w.ColorMap = qualityColorMap
|
|
||||||
w.Refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use state manager to synchronize selected value across all widgets
|
// Use state manager to synchronize selected value across all widgets
|
||||||
|
|
@ -10464,9 +10464,19 @@ var audioCtxGlobal struct {
|
||||||
|
|
||||||
func getAudioContext(sampleRate, channels, bytesPerSample int) (*oto.Context, error) {
|
func getAudioContext(sampleRate, channels, bytesPerSample int) (*oto.Context, error) {
|
||||||
audioCtxGlobal.once.Do(func() {
|
audioCtxGlobal.once.Do(func() {
|
||||||
// Increased from 2048 (42ms) to 8192 (170ms) for smoother playback
|
_ = bytesPerSample
|
||||||
// Larger buffer prevents audio stuttering and underruns
|
// Larger buffer prevents audio stuttering and underruns
|
||||||
audioCtxGlobal.ctx, audioCtxGlobal.err = oto.NewContext(sampleRate, channels, bytesPerSample, 8192)
|
ctx, ready, err := oto.NewContext(&oto.NewContextOptions{
|
||||||
|
SampleRate: sampleRate,
|
||||||
|
ChannelCount: channels,
|
||||||
|
Format: oto.FormatSignedInt16LE,
|
||||||
|
BufferSize: 170 * time.Millisecond,
|
||||||
|
})
|
||||||
|
if err == nil && ready != nil {
|
||||||
|
<-ready
|
||||||
|
}
|
||||||
|
audioCtxGlobal.ctx = ctx
|
||||||
|
audioCtxGlobal.err = err
|
||||||
})
|
})
|
||||||
return audioCtxGlobal.ctx, audioCtxGlobal.err
|
return audioCtxGlobal.ctx, audioCtxGlobal.err
|
||||||
}
|
}
|
||||||
|
|
@ -10869,17 +10879,21 @@ func (p *playSession) runAudio(offset float64) {
|
||||||
p.audioActive.Store(false)
|
p.audioActive.Store(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
player := ctx.NewPlayer()
|
pr, pw := io.Pipe()
|
||||||
|
player := ctx.NewPlayer(pr)
|
||||||
if player == nil {
|
if player == nil {
|
||||||
logging.Debug(logging.CatFFMPEG, "audio player creation failed (video-only playback)")
|
logging.Debug(logging.CatFFMPEG, "audio player creation failed (video-only playback)")
|
||||||
p.audioActive.Store(false)
|
p.audioActive.Store(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
player.Play()
|
||||||
p.audioActive.Store(true) // Mark audio as active
|
p.audioActive.Store(true) // Mark audio as active
|
||||||
localPlayer := player
|
localPlayer := player
|
||||||
go func() {
|
go func() {
|
||||||
defer cmd.Process.Kill()
|
defer cmd.Process.Kill()
|
||||||
defer localPlayer.Close()
|
defer localPlayer.Close()
|
||||||
|
defer pr.Close()
|
||||||
|
defer pw.Close()
|
||||||
defer p.audioActive.Store(false) // Mark audio as inactive when done
|
defer p.audioActive.Store(false) // Mark audio as inactive when done
|
||||||
// Increased from 4096 (21ms) to 16384 (85ms) for smoother playback
|
// Increased from 4096 (21ms) to 16384 (85ms) for smoother playback
|
||||||
// Larger chunks reduce read frequency and improve performance
|
// Larger chunks reduce read frequency and improve performance
|
||||||
|
|
@ -10905,7 +10919,10 @@ func (p *playSession) runAudio(offset float64) {
|
||||||
}
|
}
|
||||||
// Volume is now handled by FFmpeg, just write directly
|
// Volume is now handled by FFmpeg, just write directly
|
||||||
// This eliminates per-sample processing overhead
|
// This eliminates per-sample processing overhead
|
||||||
localPlayer.Write(chunk[:n])
|
if _, werr := pw.Write(chunk[:n]); werr != nil {
|
||||||
|
logging.Debug(logging.CatFFMPEG, "audio write failed: %v", werr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update audio master clock for A/V sync
|
// Update audio master clock for A/V sync
|
||||||
bytesWritten += int64(n)
|
bytesWritten += int64(n)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user