diff options
Diffstat (limited to 'soundbox')
| -rw-r--r-- | soundbox/network.go | 6 | ||||
| -rw-r--r-- | soundbox/streaming.go | 50 | ||||
| -rw-r--r-- | soundbox/url.go | 45 | 
3 files changed, 57 insertions, 44 deletions
diff --git a/soundbox/network.go b/soundbox/network.go index 6e7acea..11d9362 100644 --- a/soundbox/network.go +++ b/soundbox/network.go @@ -7,6 +7,10 @@ import (  	"time"  ) +// streamingPort is the default network port a soundbox is listening to for +// incoming audio stream data. +const streamingPort = 5316 +  const dialTimeoutSeconds = 3  // toLinkLocal converts a MAC address to the corresponding IPv6 link-local @@ -34,7 +38,7 @@ func dialContext(ctx context.Context, ha net.HardwareAddr) (net.Conn, error) {  	}  	c := make(chan net.Conn) -	dialContext, cancel := context.WithTimeout(ctx, dialTimeoutSeconds * time.Second) +	dialContext, cancel := context.WithTimeout(ctx, dialTimeoutSeconds*time.Second)  	defer cancel()  	for _, iface := range ifaces {  		go func() { diff --git a/soundbox/streaming.go b/soundbox/streaming.go new file mode 100644 index 0000000..5852dcf --- /dev/null +++ b/soundbox/streaming.go @@ -0,0 +1,50 @@ +package soundbox + +import ( +	"context" +	"errors" +	"io" +	"net" +	"time" +) + +const bufferSize = 20 + +const writeTimeout = 1 * time.Second + +func streamContext(ctx context.Context, r io.Reader, targets []net.HardwareAddr) error { +	conns := make([]net.Conn, 0) +	for _, target := range targets { +		conn, err := dialContext(ctx, target) +		if err != nil { +			return err +		} +		conns = append(conns, conn) +	} +	defer func() { +		for _, conn := range conns { +			conn.Close() +		} +	}() + +	for { +		buffer := make([]byte, bufferSize) +		i, err := r.Read(buffer) +		if err != nil { +			if errors.Is(err, io.EOF) { +				break +			} else { +				return err +			} +		} +		for _, conn := range conns { +			conn.SetDeadline(time.Now().Add(writeTimeout)) +			_, err = conn.Write(buffer[:i]) +			if err != nil { +				return err +			} +		} +	} + +	return nil +} diff --git a/soundbox/url.go b/soundbox/url.go index 4ad9908..6fed442 100644 --- a/soundbox/url.go +++ b/soundbox/url.go @@ -2,39 +2,14 @@ package soundbox  import (  	"context" -	"errors" -	"io"  	"net"  	"os/exec" -	"time"  ) -// streamingPort is the default network port a soundbox is listening to for -// incoming audio stream data. -const streamingPort = 5316 - -const bufferSize = 20 - -const writeTimeout = 1 * time.Second -  // StreamURLContext streams audio from a given URL to one or multiple soundbox  // devices. The devices are referenced via their MAC addresses given by the  // targets argument. The ctx argument is passed to cancel the streaming.  func StreamURLContext(ctx context.Context, url string, targets []net.HardwareAddr) error { -	conns := make([]net.Conn, 0) -	for _, target := range targets { -		conn, err := dialContext(ctx, target) -		if err != nil { -			return err -		} -		conns = append(conns, conn) -	} -	defer func() { -		for _, conn := range conns { -			conn.Close() -		} -	}() -  	cmd := exec.CommandContext(  		ctx,  		"ffmpeg", @@ -47,6 +22,7 @@ func StreamURLContext(ctx context.Context, url string, targets []net.HardwareAdd  		"ogg",  		"-",  	) +  	stdout, err := cmd.StdoutPipe()  	if err != nil {  		return err @@ -57,24 +33,7 @@ func StreamURLContext(ctx context.Context, url string, targets []net.HardwareAdd  		return err  	} -	for { -		buffer := make([]byte, bufferSize) -		i, err := stdout.Read(buffer) -		if err != nil { -			if errors.Is(err, io.EOF) { -				break -			} else { -				return err -			} -		} -		for _, conn := range conns { -			conn.SetDeadline(time.Now().Add(writeTimeout)) -			_, err = conn.Write(buffer[:i]) -			if err != nil { -				return err -			} -		} -	} +	streamContext(ctx, stdout, targets)  	return cmd.Wait()  }  | 
