Skip to content

Commit

Permalink
[squeezebox] Support for more audio streams through the audio servlet (
Browse files Browse the repository at this point in the history
…openhab#15194)

* [squeezebox] Support for more audio streams through the audio servlet

Audio sink supporting more audio streams

---------

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
Signed-off-by: Jørgen Austvik <jaustvik@acm.org>
  • Loading branch information
dalgwen authored and austvik committed Mar 27, 2024
1 parent 5d2be15 commit 0584d92
Showing 1 changed file with 51 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<AudioFormat> SUPPORTED_FORMATS = new HashSet<>();
private static final HashSet<Class<? extends AudioStream>> SUPPORTED_STREAMS = new HashSet<>();
private static final Set<AudioFormat> SUPPORTED_FORMATS = Set.of(AudioFormat.WAV, AudioFormat.MP3);
private static final Set<Class<? extends AudioStream>> 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;

Expand All @@ -81,43 +76,64 @@ 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;
tryClose(audioStream);
} 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");
tryClose(audioStream);
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<AudioFormat> getSupportedFormats() {
return SUPPORTED_FORMATS;
Expand Down

0 comments on commit 0584d92

Please sign in to comment.