Skip to content

Commit

Permalink
[allplay] Support for more audio streams through the HTTP audio servl…
Browse files Browse the repository at this point in the history
…et (openhab#15201)

* [allplay] Support for more audio streams through the HTTP audio servlet

Related to openhab#15113

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
Signed-off-by: Jørgen Austvik <jaustvik@acm.org>
  • Loading branch information
lolodomo authored and austvik committed Mar 27, 2024
1 parent f344881 commit 1ea5147
Showing 1 changed file with 45 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
package org.openhab.binding.allplay.internal;

import java.io.IOException;
import java.util.HashSet;
import java.io.InputStream;
import java.util.Locale;
import java.util.Set;

import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.allplay.internal.handler.AllPlayHandler;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioHTTPServer;
import org.openhab.core.audio.AudioSink;
import org.openhab.core.audio.AudioSinkAsync;
import org.openhab.core.audio.AudioStream;
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 @@ -36,23 +39,16 @@
*
* @author Dominic Lerbs - Initial contribution
*/
public class AllPlayAudioSink implements AudioSink {
public class AllPlayAudioSink extends AudioSinkAsync {

private final Logger logger = LoggerFactory.getLogger(AllPlayAudioSink.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.MP3, AudioFormat.WAV);
private static final Set<Class<? extends AudioStream>> SUPPORTED_STREAMS = Set.of(AudioStream.class);
private final AllPlayHandler handler;
private final AudioHTTPServer audioHTTPServer;
private final String callbackUrl;

static {
SUPPORTED_FORMATS.add(AudioFormat.MP3);
SUPPORTED_FORMATS.add(AudioFormat.WAV);

SUPPORTED_STREAMS.add(AudioStream.class);
}

/**
* @param handler The related {@link AllPlayHandler}
* @param audioHTTPServer The {@link AudioHTTPServer} for serving the stream
Expand All @@ -75,13 +71,41 @@ public String getLabel(Locale locale) {
}

@Override
public void process(AudioStream audioStream)
protected void processAsynchronously(@Nullable AudioStream audioStream)
throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
if (audioStream == null) {
return;
}
String url;
if (audioStream instanceof URLAudioStream urlAudioStream) {
// it is an external URL, the speaker can access it itself and play it
url = urlAudioStream.getURL();
tryClose(audioStream);
} else if (callbackUrl != null) {
StreamServed streamServed;
try {
streamServed = audioHTTPServer.serve(audioStream, 10, true);
} catch (IOException e) {
tryClose(audioStream);
throw new UnsupportedAudioStreamException(
"AllPlay was not able to handle the audio stream (cache on disk failed).",
audioStream.getClass(), e);
}
url = callbackUrl + streamServed.url();
streamServed.playEnd().thenRun(() -> this.playbackFinished(audioStream));
} else {
logger.warn("We do not have any callback url, so AllPlay cannot play the audio stream!");
tryClose(audioStream);
return;
}
try {
String url = convertAudioStreamToUrl(audioStream);
handler.playUrl(url);
} catch (SpeakerException | AllPlayCallbackException e) {
logger.warn("Unable to play audio stream on speaker {}", getId(), e);
} catch (SpeakerException e) {
if (logger.isDebugEnabled()) {
logger.warn("Unable to play audio stream on speaker {}", getId(), e);
} else {
logger.warn("Unable to play audio stream on speaker {}: {}", getId(), e.getMessage());
}
}
}

Expand Down Expand Up @@ -113,36 +137,12 @@ public void setVolume(PercentType volume) throws IOException {
}
}

/**
* Converts the given {@link AudioStream} into an URL which can be used for streaming.
*
* @param audioStream The incoming {@link AudioStream}
* @return The URL to use for streaming
* @throws AllPlayCallbackException Exception if the URL cannot be created
*/
private String convertAudioStreamToUrl(AudioStream audioStream) throws AllPlayCallbackException {
if (audioStream instanceof URLAudioStream) {
// it is an external URL, the speaker can access it itself and play it
return ((URLAudioStream) audioStream).getURL();
} else {
return createUrlForLocalHttpServer(audioStream);
}
}

private String createUrlForLocalHttpServer(AudioStream audioStream) throws AllPlayCallbackException {
if (callbackUrl != null) {
String relativeUrl = audioHTTPServer.serve(audioStream);
return callbackUrl + relativeUrl;
} else {
throw new AllPlayCallbackException("Unable to play audio stream as callback URL is not set");
}
}

@SuppressWarnings("serial")
private class AllPlayCallbackException extends Exception {

public AllPlayCallbackException(String message) {
super(message);
private void tryClose(@Nullable InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {
}
}
}
}

0 comments on commit 1ea5147

Please sign in to comment.