fix: changing channels quickly causes two to play
This commit is contained in:
parent
8782746579
commit
36059f23ac
4 changed files with 42 additions and 11 deletions
20
app/app.go
20
app/app.go
|
|
@ -2,6 +2,7 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
c "context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -103,25 +104,36 @@ func Play(ctx *context.AppContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.IsPlaying = true
|
ctx.IsPlaying = true
|
||||||
|
streamCtx, cancel := c.WithCancel(c.Background())
|
||||||
|
ctx.StreamCancel = cancel
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
req, _ := http.NewRequest("GET", chn.Playlist, nil)
|
req, _ := http.NewRequestWithContext(streamCtx, "GET", chn.Playlist, nil)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
if streamCtx.Err() == nil {
|
||||||
|
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
if streamCtx.Err() == nil {
|
||||||
|
ctx.SetStatusMessage(fmt.Sprintf("Unable to stream channel: %s. Try again.", chn.Name))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if streamURL, ok := difm.GetStreamURL(body, ctx); ok {
|
if streamURL, ok := difm.GetStreamURL(body, ctx); ok {
|
||||||
|
select {
|
||||||
|
case <-streamCtx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
UpdateNowPlaying(ctx, chn)
|
UpdateNowPlaying(ctx, chn)
|
||||||
difm.Stream(streamURL, ctx)
|
difm.Stream(streamURL, ctx, streamCtx)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
c "context"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -40,6 +41,7 @@ type AppContext struct {
|
||||||
Player *pulse.PlaybackStream
|
Player *pulse.PlaybackStream
|
||||||
ShowStatus bool // The status pane will be visible when true
|
ShowStatus bool // The status pane will be visible when true
|
||||||
StatusChannel chan components.StatusMessage
|
StatusChannel chan components.StatusMessage
|
||||||
|
StreamCancel c.CancelFunc
|
||||||
View *views.ViewContext
|
View *views.ViewContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
28
difm/difm.go
28
difm/difm.go
|
|
@ -219,20 +219,25 @@ func ListFavorites(ctx *context.AppContext) (favorites []components.FavoriteItem
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream streams the provided URL using the given di.fm premium token
|
// Stream streams the provided URL using the given di.fm premium token
|
||||||
func Stream(url string, ctx *context.AppContext) {
|
func Stream(url string, ctx *context.AppContext, streamCtx c.Context) {
|
||||||
client := http.DefaultClient
|
client := http.DefaultClient
|
||||||
u := fmt.Sprintf("%s?%s", url, config.GetToken())
|
u := fmt.Sprintf("%s?%s", url, config.GetToken())
|
||||||
|
|
||||||
// Keep increasing playback latency by one second for every time that the player exits with EOF
|
// Keep increasing playback latency by one second for every time that the player exits with EOF
|
||||||
// while ctx.IsPlaying
|
// while ctx.IsPlaying
|
||||||
for playbackLatency := 1; ctx.IsPlaying; playbackLatency++ {
|
for playbackLatency := 1; ; playbackLatency++ {
|
||||||
|
select {
|
||||||
|
case <-streamCtx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
ctx.SetStatusMessage("Buffering stream...")
|
ctx.SetStatusMessage("Buffering stream...")
|
||||||
if ctx.Player != nil {
|
if ctx.Player != nil {
|
||||||
ctx.Player.Close()
|
ctx.Player.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
rctx := c.Background()
|
req, err := http.NewRequestWithContext(streamCtx, "GET", u, nil)
|
||||||
req, err := http.NewRequestWithContext(rctx, "GET", u, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SetStatusMessage("There was a problem streaming audio!")
|
ctx.SetStatusMessage("There was a problem streaming audio!")
|
||||||
return
|
return
|
||||||
|
|
@ -241,6 +246,9 @@ func Stream(url string, ctx *context.AppContext) {
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
|
if streamCtx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx.SetStatusMessage(fmt.Sprintf("There was a problem streaming audio: %s", err.Error()))
|
ctx.SetStatusMessage(fmt.Sprintf("There was a problem streaming audio: %s", err.Error()))
|
||||||
return
|
return
|
||||||
case resp.StatusCode != 200:
|
case resp.StatusCode != 200:
|
||||||
|
|
@ -254,14 +262,20 @@ func Stream(url string, ctx *context.AppContext) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
_, err = io.CopyN(audioStream, resp.Body, 512)
|
_, copyErr := io.CopyN(audioStream, resp.Body, 512)
|
||||||
if err != nil {
|
if copyErr != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(time.Duration(playbackLatency) * time.Second)
|
select {
|
||||||
|
case <-streamCtx.Done():
|
||||||
|
resp.Body.Close()
|
||||||
|
return
|
||||||
|
case <-time.After(time.Duration(playbackLatency) * time.Second):
|
||||||
|
}
|
||||||
|
|
||||||
err = player.Play(ctx, audioStream, playbackLatency)
|
err = player.Play(ctx, audioStream, playbackLatency)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ func Play(ctx *context.AppContext, stream io.ReadWriter, playbackLatency int) (e
|
||||||
|
|
||||||
func Stop(ctx *context.AppContext) {
|
func Stop(ctx *context.AppContext) {
|
||||||
ctx.IsPlaying = false
|
ctx.IsPlaying = false
|
||||||
|
if ctx.StreamCancel != nil {
|
||||||
|
ctx.StreamCancel()
|
||||||
|
}
|
||||||
if ctx.Player != nil {
|
if ctx.Player != nil {
|
||||||
ctx.AudioStream.Close()
|
ctx.AudioStream.Close()
|
||||||
ctx.Player.Close()
|
ctx.Player.Close()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue