[amplipi] Support for more audio streams through the HTTP audio servlet (#15199)
Related to #15113 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
2d75536f48
commit
365e900a1f
@ -13,6 +13,7 @@
|
|||||||
package org.openhab.binding.amplipi.internal.audio;
|
package org.openhab.binding.amplipi.internal.audio;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -20,9 +21,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.amplipi.internal.AmpliPiHandler;
|
import org.openhab.binding.amplipi.internal.AmpliPiHandler;
|
||||||
import org.openhab.core.audio.AudioFormat;
|
import org.openhab.core.audio.AudioFormat;
|
||||||
import org.openhab.core.audio.AudioSink;
|
import org.openhab.core.audio.AudioSinkSync;
|
||||||
import org.openhab.core.audio.AudioStream;
|
import org.openhab.core.audio.AudioStream;
|
||||||
import org.openhab.core.audio.FixedLengthAudioStream;
|
import org.openhab.core.audio.StreamServed;
|
||||||
import org.openhab.core.audio.URLAudioStream;
|
import org.openhab.core.audio.URLAudioStream;
|
||||||
import org.openhab.core.audio.UnsupportedAudioFormatException;
|
import org.openhab.core.audio.UnsupportedAudioFormatException;
|
||||||
import org.openhab.core.audio.UnsupportedAudioStreamException;
|
import org.openhab.core.audio.UnsupportedAudioStreamException;
|
||||||
@ -39,59 +40,66 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class PAAudioSink implements AudioSink, ThingHandlerService {
|
public class PAAudioSink extends AudioSinkSync implements ThingHandlerService {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(PAAudioSink.class);
|
private final Logger logger = LoggerFactory.getLogger(PAAudioSink.class);
|
||||||
|
|
||||||
private static final Set<AudioFormat> SUPPORTED_AUDIO_FORMATS = Set.of(AudioFormat.MP3, AudioFormat.WAV);
|
private static final Set<AudioFormat> SUPPORTED_AUDIO_FORMATS = Set.of(AudioFormat.MP3, AudioFormat.WAV);
|
||||||
private static final Set<Class<? extends AudioStream>> SUPPORTED_AUDIO_STREAMS = Set
|
private static final Set<Class<? extends AudioStream>> SUPPORTED_AUDIO_STREAMS = Set.of(AudioStream.class);
|
||||||
.of(FixedLengthAudioStream.class, URLAudioStream.class);
|
|
||||||
|
|
||||||
private @Nullable AmpliPiHandler handler;
|
private @Nullable AmpliPiHandler handler;
|
||||||
|
|
||||||
private @Nullable PercentType volume;
|
private @Nullable PercentType volume;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(@Nullable AudioStream audioStream)
|
protected void processSynchronously(@Nullable AudioStream audioStream)
|
||||||
throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
|
throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
|
||||||
if (audioStream == null) {
|
if (audioStream == null) {
|
||||||
// in case the audioStream is null, this should be interpreted as a request to end any currently playing
|
// in case the audioStream is null, this should be interpreted as a request to end any currently playing
|
||||||
// stream.
|
// stream.
|
||||||
logger.debug("Web Audio sink does not support stopping the currently playing stream.");
|
logger.debug("AmpliPi sink does not support stopping the currently playing stream.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AmpliPiHandler localHandler = this.handler;
|
AmpliPiHandler localHandler = this.handler;
|
||||||
if (localHandler != null) {
|
if (localHandler == null) {
|
||||||
try (AudioStream stream = audioStream) {
|
tryClose(audioStream);
|
||||||
logger.debug("Received audio stream of format {}", audioStream.getFormat());
|
return;
|
||||||
String audioUrl;
|
}
|
||||||
if (audioStream instanceof URLAudioStream) {
|
logger.debug("Received audio stream of format {}", audioStream.getFormat());
|
||||||
// it is an external URL, so we can directly pass this on.
|
String callbackUrl = localHandler.getCallbackUrl();
|
||||||
URLAudioStream urlAudioStream = (URLAudioStream) audioStream;
|
String audioUrl;
|
||||||
audioUrl = urlAudioStream.getURL();
|
if (audioStream instanceof URLAudioStream urlAudioStream) {
|
||||||
} else if (audioStream instanceof FixedLengthAudioStream) {
|
// it is an external URL, so we can directly pass this on.
|
||||||
String callbackUrl = localHandler.getCallbackUrl();
|
audioUrl = urlAudioStream.getURL();
|
||||||
if (callbackUrl == null) {
|
tryClose(audioStream);
|
||||||
throw new UnsupportedAudioStreamException(
|
} else if (callbackUrl != null) {
|
||||||
"Cannot play audio since no callback url is available.", audioStream.getClass());
|
// we need to serve it for a while
|
||||||
} else {
|
StreamServed streamServed;
|
||||||
// we need to serve it for a while, hence only
|
try {
|
||||||
// FixedLengthAudioStreams are supported.
|
streamServed = localHandler.getAudioHTTPServer().serve(audioStream, 10, true);
|
||||||
String relativeUrl = localHandler.getAudioHTTPServer()
|
|
||||||
.serve((FixedLengthAudioStream) audioStream, 10).toString();
|
|
||||||
audioUrl = callbackUrl + relativeUrl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedAudioStreamException(
|
|
||||||
"Web audio sink can only handle FixedLengthAudioStreams and URLAudioStreams.",
|
|
||||||
audioStream.getClass());
|
|
||||||
}
|
|
||||||
localHandler.playPA(audioUrl, volume);
|
|
||||||
// we reset the volume value again, so that a next invocation without a volume will again use the zones
|
|
||||||
// defaults.
|
|
||||||
volume = null;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("Error while closing the audio stream: {}", e.getMessage(), e);
|
tryClose(audioStream);
|
||||||
|
throw new UnsupportedAudioStreamException(
|
||||||
|
"AmpliPi was not able to handle the audio stream (cache on disk failed).",
|
||||||
|
audioStream.getClass(), e);
|
||||||
|
}
|
||||||
|
audioUrl = callbackUrl + streamServed.url();
|
||||||
|
} else {
|
||||||
|
logger.warn("We do not have any callback url, so AmpliPi cannot play the audio stream!");
|
||||||
|
tryClose(audioStream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localHandler.playPA(audioUrl, volume);
|
||||||
|
// we reset the volume value again, so that a next invocation without a volume will again use the zones
|
||||||
|
// defaults.
|
||||||
|
volume = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryClose(@Nullable InputStream is) {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user