summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--soundbox/network.go6
-rw-r--r--soundbox/streaming.go50
-rw-r--r--soundbox/url.go45
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()
}