[freeboxos] Align audio sink to freebox binding (#15207)

Related to #15113

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2023-07-12 11:52:06 +02:00 committed by GitHub
parent 18ae834d68
commit 5c32f80c3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -15,6 +15,7 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.core.audio.AudioFormat.*; import static org.openhab.core.audio.AudioFormat.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@ -47,7 +48,8 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault @NonNullByDefault
public class AirMediaSink extends AudioSinkAsync { public class AirMediaSink extends AudioSinkAsync {
private static final Set<Class<? extends AudioStream>> SUPPORTED_STREAMS = Set.of(AudioStream.class); private static final Set<Class<? extends AudioStream>> SUPPORTED_STREAMS = Set.of(AudioStream.class);
private static final Set<AudioFormat> BASIC_FORMATS = Set.of(WAV, OGG); // OGG seems to not be properly supported (tested with a file produced by VoiceRSS)
private static final Set<AudioFormat> BASIC_FORMATS = Set.of(WAV/* , OGG */);
private static final Set<AudioFormat> ALL_MP3_FORMATS = Set.of( private static final Set<AudioFormat> ALL_MP3_FORMATS = Set.of(
new AudioFormat(CONTAINER_NONE, CODEC_MP3, null, null, 96000, null), new AudioFormat(CONTAINER_NONE, CODEC_MP3, null, null, 96000, null),
new AudioFormat(CONTAINER_NONE, CODEC_MP3, null, null, 112000, null), new AudioFormat(CONTAINER_NONE, CODEC_MP3, null, null, 112000, null),
@ -111,46 +113,69 @@ public class AirMediaSink extends AudioSinkAsync {
@Override @Override
protected void processAsynchronously(@Nullable AudioStream audioStream) protected void processAsynchronously(@Nullable AudioStream audioStream)
throws UnsupportedAudioFormatException, UnsupportedAudioStreamException { throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
if (thingHandler.getThing().getStatus() == ThingStatus.ONLINE) { if (thingHandler.getThing().getStatus() != ThingStatus.ONLINE) {
try { tryClose(audioStream);
MediaReceiverManager manager = thingHandler.getManager(MediaReceiverManager.class);
if (audioStream == null) {
manager.sendToReceiver(playerName, password, Action.STOP, MediaType.VIDEO);
return; return;
} }
if (audioStream instanceof URLAudioStream urlAudioStream) { if (audioStream == null) {
// it is an external URL, we can access it directly stopMedia();
logger.debug("AirPlay audio sink: process url {}", urlAudioStream.getURL());
playMedia(manager, urlAudioStream.getURL());
return; return;
} }
String url;
if (audioStream instanceof URLAudioStream urlAudioStream) {
// it is an external URL, we can access it directly
url = urlAudioStream.getURL();
tryClose(audioStream);
} else {
// we serve it on our own HTTP server // we serve it on our own HTTP server
logger.debug("audioStream {} {}", audioStream.getClass().getSimpleName(), audioStream.getFormat());
StreamServed streamServed; StreamServed streamServed;
try { try {
streamServed = audioHTTPServer.serve(audioStream, 5, true); streamServed = audioHTTPServer.serve(audioStream, 5, true);
} catch (IOException e) { } catch (IOException e) {
try { tryClose(audioStream);
audioStream.close();
} catch (IOException ex) {
logger.debug("Exception while closing audioStream");
}
throw new UnsupportedAudioStreamException( throw new UnsupportedAudioStreamException(
"AirPlay device was not able to handle the audio stream (cache on disk failed).", "AirPlay device was not able to handle the audio stream (cache on disk failed).",
audioStream.getClass(), e); audioStream.getClass(), e);
} }
streamServed.playEnd().thenRun(() -> this.playbackFinished(audioStream)); url = callbackUrl + streamServed.url();
logger.debug("AirPlay audio sink: process url {}", callbackUrl + streamServed.url()); streamServed.playEnd().thenRun(() -> {
playMedia(manager, callbackUrl + streamServed.url()); stopMedia();
} catch (FreeboxException e) { this.playbackFinished(audioStream);
logger.warn("Audio stream playback failed: {}", e.getMessage()); });
}
logger.debug("AirPlay audio sink: process url {}", url);
playMedia(url);
}
private void tryClose(@Nullable InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {
} }
} }
} }
private void playMedia(MediaReceiverManager manager, String url) throws FreeboxException { private void playMedia(String url) {
try {
MediaReceiverManager manager = thingHandler.getManager(MediaReceiverManager.class);
manager.sendToReceiver(playerName, password, Action.STOP, MediaType.VIDEO); manager.sendToReceiver(playerName, password, Action.STOP, MediaType.VIDEO);
manager.sendToReceiver(playerName, password, Action.START, MediaType.VIDEO, url); manager.sendToReceiver(playerName, password, Action.START, MediaType.VIDEO, url);
} catch (FreeboxException e) {
logger.warn("Playing media failed: {}", e.getMessage());
}
}
private void stopMedia() {
try {
MediaReceiverManager manager = thingHandler.getManager(MediaReceiverManager.class);
manager.sendToReceiver(playerName, password, Action.STOP, MediaType.VIDEO);
} catch (FreeboxException e) {
logger.warn("Stopping media failed: {}", e.getMessage());
}
} }
@Override @Override