diff --git a/.github/workflows/main-tests.yml b/.github/workflows/main-tests.yml index a8ed260..1f12d91 100644 --- a/.github/workflows/main-tests.yml +++ b/.github/workflows/main-tests.yml @@ -12,7 +12,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: "1.22" + go-version: "1.23" - name: Install libgstreamer1.0-dev run: | sudo apt-get install -y libunwind-dev @@ -27,7 +27,7 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 22.x - name: Install Packages run: cd client && yarn install --frozen-lockfile - name: Build Client diff --git a/go.mod b/go.mod index bf8210c..ca81643 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ahamlinman/hypcast -go 1.22 +go 1.23.0 require ( github.com/google/go-cmp v0.6.0 diff --git a/internal/api/api.go b/internal/api/api.go index afb68da..6accd1c 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -6,6 +6,7 @@ import ( "errors" "log/slog" "net/http" + "slices" "github.com/gorilla/websocket" @@ -50,7 +51,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *Handler) handleConfigChannels(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - json.NewEncoder(w).Encode(h.tuner.ChannelNames()) + json.NewEncoder(w).Encode(slices.Collect(h.tuner.ChannelNames())) } func (h *Handler) rpcStop(r *http.Request, _ struct{}) (code int, body any) { diff --git a/internal/atsc/tuner/tuner.go b/internal/atsc/tuner/tuner.go index 201fdde..1ae855c 100644 --- a/internal/atsc/tuner/tuner.go +++ b/internal/atsc/tuner/tuner.go @@ -5,6 +5,7 @@ package tuner import ( "errors" "fmt" + "iter" "log/slog" "strings" "sync" @@ -111,21 +112,23 @@ func NewTuner(channels []atsc.Channel, videoPipeline VideoPipeline) *Tuner { } func makeChannelMap(channels []atsc.Channel) map[string]atsc.Channel { - m := make(map[string]atsc.Channel) - for _, c := range channels { - m[c.Name] = c + m := make(map[string]atsc.Channel, len(channels)) + for _, ch := range channels { + m[ch.Name] = ch } return m } -// ChannelNames returns the names of channels that are known to this tuner and -// may be passed to Tune. -func (t *Tuner) ChannelNames() []string { - channelNames := make([]string, len(t.channels)) - for i, ch := range t.channels { - channelNames[i] = ch.Name +// ChannelNames returns an iterator over the names of channels that may be +// passed to [Tuner.Tune]. +func (t *Tuner) ChannelNames() iter.Seq[string] { + return func(yield func(string) bool) { + for _, ch := range t.channels { + if !yield(ch.Name) { + break + } + } } - return channelNames } // WatchStatus sets up a handler function to continuously receive the status of @@ -201,14 +204,8 @@ func (t *Tuner) Tune(channelName string) (err error) { } slog.Info("Started transcode pipeline") - t.status.Set(Status{ - State: StatePlaying, - ChannelName: channelName, - }) - t.tracks.Set(Tracks{ - Video: vt, - Audio: at, - }) + t.status.Set(Status{State: StatePlaying, ChannelName: channelName}) + t.tracks.Set(Tracks{Video: vt, Audio: at}) return nil } @@ -296,7 +293,6 @@ func (t *Tuner) destroyAnyRunningPipeline() error { if t.pipeline == nil { return nil } - err := t.pipeline.Close() t.pipeline = nil slog.Info("Destroyed transcode pipeline", "error", err) @@ -335,13 +331,9 @@ var ( func (t *Tuner) createTrackPair() (video, audio *webrtc.TrackLocalStaticSample, err error) { streamID := fmt.Sprintf("Tuner(%p)", t) - - video, err = webrtc.NewTrackLocalStaticSample(VideoCodecCapability, streamID, streamID) - if err != nil { - return - } - - audio, err = webrtc.NewTrackLocalStaticSample(AudioCodecCapability, streamID, streamID) + video, verr := webrtc.NewTrackLocalStaticSample(VideoCodecCapability, streamID, streamID) + audio, aerr := webrtc.NewTrackLocalStaticSample(AudioCodecCapability, streamID, streamID) + err = errors.Join(verr, aerr) return }