From 0f8ddcaabbd40e8818a97a53b5c172abd0c60571 Mon Sep 17 00:00:00 2001 From: Gwendal Roulleau Date: Thu, 6 Jul 2023 19:43:57 +0200 Subject: [PATCH 1/2] [squeezebox] Support for more audio streams through the audio servlet Audio sink supporting more audio streams Signed-off-by: Gwendal Roulleau --- .../internal/SqueezeBoxAudioSink.java | 84 +++++++++++-------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java index 7ead4a125887a..6d9c0668d3fa4 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java @@ -12,17 +12,20 @@ */ package org.openhab.binding.squeezebox.internal; -import java.util.HashSet; +import java.io.IOException; +import java.io.InputStream; import java.util.Locale; import java.util.Set; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.squeezebox.internal.handler.SqueezeBoxPlayerHandler; import org.openhab.core.audio.AudioFormat; import org.openhab.core.audio.AudioHTTPServer; import org.openhab.core.audio.AudioSink; +import org.openhab.core.audio.AudioSinkSync; import org.openhab.core.audio.AudioStream; import org.openhab.core.audio.FileAudioStream; -import org.openhab.core.audio.FixedLengthAudioStream; +import org.openhab.core.audio.StreamServed; import org.openhab.core.audio.URLAudioStream; import org.openhab.core.audio.UnsupportedAudioFormatException; import org.openhab.core.audio.UnsupportedAudioStreamException; @@ -38,25 +41,17 @@ * @author Mark Hilbush - Initial contribution * @author Mark Hilbush - Add callbackUrl */ -public class SqueezeBoxAudioSink implements AudioSink { +public class SqueezeBoxAudioSink extends AudioSinkSync { private final Logger logger = LoggerFactory.getLogger(SqueezeBoxAudioSink.class); - private static final HashSet SUPPORTED_FORMATS = new HashSet<>(); - private static final HashSet> SUPPORTED_STREAMS = new HashSet<>(); + private static final Set SUPPORTED_FORMATS = Set.of(AudioFormat.WAV, AudioFormat.MP3); + private static final Set> SUPPORTED_STREAMS = Set.of(AudioStream.class); // Needed because Squeezebox does multiple requests for the stream - private static final int STREAM_TIMEOUT = 15; + private static final int STREAM_TIMEOUT = 10; private String callbackUrl; - static { - SUPPORTED_FORMATS.add(AudioFormat.WAV); - SUPPORTED_FORMATS.add(AudioFormat.MP3); - - SUPPORTED_STREAMS.add(FixedLengthAudioStream.class); - SUPPORTED_STREAMS.add(URLAudioStream.class); - } - private AudioHTTPServer audioHTTPServer; private SqueezeBoxPlayerHandler playerHandler; @@ -81,43 +76,62 @@ public String getLabel(Locale locale) { } @Override - public void process(AudioStream audioStream) + public void processSynchronously(AudioStream audioStream) throws UnsupportedAudioFormatException, UnsupportedAudioStreamException { + if (audioStream == null) { + return; + } AudioFormat format = audioStream.getFormat(); if (!AudioFormat.WAV.isCompatible(format) && !AudioFormat.MP3.isCompatible(format)) { + tryClose(audioStream); throw new UnsupportedAudioFormatException("Currently only MP3 and WAV formats are supported: ", format); } String url; if (audioStream instanceof URLAudioStream) { url = ((URLAudioStream) audioStream).getURL(); - } else if (audioStream instanceof FixedLengthAudioStream) { - // Since Squeezebox will make multiple requests for the stream, set a timeout on the stream - url = audioHTTPServer.serve((FixedLengthAudioStream) audioStream, STREAM_TIMEOUT).toString(); - - if (AudioFormat.WAV.isCompatible(format)) { - url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.WAV_EXTENSION; - } else if (AudioFormat.MP3.isCompatible(format)) { - url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.MP3_EXTENSION; - } - - // Form the URL for streaming the notification from the OH2 web server - // Use the callback URL if it is set in the binding configuration - String host = callbackUrl == null || callbackUrl.isEmpty() ? playerHandler.getHostAndPort() : callbackUrl; - if (host == null) { - logger.warn("Unable to get host/port from which to stream notification"); - return; - } - url = host + url; } else { - throw new UnsupportedAudioStreamException( - "SqueezeBox can only handle URLAudioStream or FixedLengthAudioStreams.", null); + try { + // Since Squeezebox will make multiple requests for the stream, set multiple to true + StreamServed streamServed = audioHTTPServer.serve(audioStream, STREAM_TIMEOUT, true); + url = streamServed.url(); + + if (AudioFormat.WAV.isCompatible(format)) { + url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.WAV_EXTENSION; + } else if (AudioFormat.MP3.isCompatible(format)) { + url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.MP3_EXTENSION; + } + + // Form the URL for streaming the notification from the OH web server + // Use the callback URL if it is set in the binding configuration + String host = callbackUrl == null || callbackUrl.isEmpty() ? playerHandler.getHostAndPort() + : callbackUrl; + if (host == null) { + logger.warn("Unable to get host/port from which to stream notification"); + return; + } + url = host + url; + } catch (IOException e) { + tryClose(audioStream); + throw new UnsupportedAudioStreamException( + "Squeezebox binding was not able to handle the audio stream (cache on disk failed)", + audioStream.getClass(), e); + } } logger.debug("Processing audioStream {} of format {}", url, format); playerHandler.playNotificationSoundURI(new StringType(url)); } + private void tryClose(@Nullable InputStream is) { + if (is != null) { + try { + is.close(); + } catch (IOException ignored) { + } + } + } + @Override public Set getSupportedFormats() { return SUPPORTED_FORMATS; From 0e8a5b9867f043819bf52e7d5f275ca840fcf3bd Mon Sep 17 00:00:00 2001 From: Gwendal Roulleau Date: Thu, 6 Jul 2023 20:44:32 +0200 Subject: [PATCH 2/2] [squeezebox] Support for more audio streams through the audio servlet Apply code review Signed-off-by: Gwendal Roulleau --- .../binding/squeezebox/internal/SqueezeBoxAudioSink.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java index 6d9c0668d3fa4..6fdf586b1c0a6 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/SqueezeBoxAudioSink.java @@ -90,6 +90,7 @@ public void processSynchronously(AudioStream audioStream) String url; if (audioStream instanceof URLAudioStream) { url = ((URLAudioStream) audioStream).getURL(); + tryClose(audioStream); } else { try { // Since Squeezebox will make multiple requests for the stream, set multiple to true @@ -108,6 +109,7 @@ public void processSynchronously(AudioStream audioStream) : callbackUrl; if (host == null) { logger.warn("Unable to get host/port from which to stream notification"); + tryClose(audioStream); return; } url = host + url;