2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.allplay.internal;
15 import java.io.IOException;
16 import java.util.HashSet;
17 import java.util.Locale;
20 import org.openhab.binding.allplay.internal.handler.AllPlayHandler;
21 import org.openhab.core.audio.AudioFormat;
22 import org.openhab.core.audio.AudioHTTPServer;
23 import org.openhab.core.audio.AudioSink;
24 import org.openhab.core.audio.AudioStream;
25 import org.openhab.core.audio.URLAudioStream;
26 import org.openhab.core.audio.UnsupportedAudioFormatException;
27 import org.openhab.core.audio.UnsupportedAudioStreamException;
28 import org.openhab.core.library.types.PercentType;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import de.kaizencode.tchaikovsky.exception.SpeakerException;
35 * The {@link AllPlayAudioSink} make AllPlay speakers available as an {@link AudioSink}.
37 * @author Dominic Lerbs - Initial contribution
39 public class AllPlayAudioSink implements AudioSink {
41 private final Logger logger = LoggerFactory.getLogger(AllPlayAudioSink.class);
43 private static final HashSet<AudioFormat> SUPPORTED_FORMATS = new HashSet<>();
44 private static final HashSet<Class<? extends AudioStream>> SUPPORTED_STREAMS = new HashSet<>();
45 private final AllPlayHandler handler;
46 private final AudioHTTPServer audioHTTPServer;
47 private final String callbackUrl;
50 SUPPORTED_FORMATS.add(AudioFormat.MP3);
51 SUPPORTED_FORMATS.add(AudioFormat.WAV);
53 SUPPORTED_STREAMS.add(AudioStream.class);
57 * @param handler The related {@link AllPlayHandler}
58 * @param audioHTTPServer The {@link AudioHTTPServer} for serving the stream
59 * @param callbackUrl The callback URL to stream the audio from
61 public AllPlayAudioSink(AllPlayHandler handler, AudioHTTPServer audioHTTPServer, String callbackUrl) {
62 this.handler = handler;
63 this.audioHTTPServer = audioHTTPServer;
64 this.callbackUrl = callbackUrl;
68 public String getId() {
69 return handler.getThing().getUID().toString();
73 public String getLabel(Locale locale) {
74 return handler.getThing().getLabel();
78 public void process(AudioStream audioStream)
79 throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
81 String url = convertAudioStreamToUrl(audioStream);
83 } catch (SpeakerException | AllPlayCallbackException e) {
84 logger.warn("Unable to play audio stream on speaker {}", getId(), e);
89 public Set<AudioFormat> getSupportedFormats() {
90 return SUPPORTED_FORMATS;
94 public Set<Class<? extends AudioStream>> getSupportedStreams() {
95 return SUPPORTED_STREAMS;
99 public PercentType getVolume() throws IOException {
101 return handler.getVolume();
102 } catch (SpeakerException e) {
103 throw new IOException(e);
108 public void setVolume(PercentType volume) throws IOException {
110 handler.handleVolumeCommand(volume);
111 } catch (SpeakerException e) {
112 throw new IOException(e);
117 * Converts the given {@link AudioStream} into an URL which can be used for streaming.
119 * @param audioStream The incoming {@link AudioStream}
120 * @return The URL to use for streaming
121 * @throws AllPlayCallbackException Exception if the URL cannot be created
123 private String convertAudioStreamToUrl(AudioStream audioStream) throws AllPlayCallbackException {
124 if (audioStream instanceof URLAudioStream) {
125 // it is an external URL, the speaker can access it itself and play it
126 return ((URLAudioStream) audioStream).getURL();
128 return createUrlForLocalHttpServer(audioStream);
132 private String createUrlForLocalHttpServer(AudioStream audioStream) throws AllPlayCallbackException {
133 if (callbackUrl != null) {
134 String relativeUrl = audioHTTPServer.serve(audioStream);
135 return callbackUrl + relativeUrl;
137 throw new AllPlayCallbackException("Unable to play audio stream as callback URL is not set");
141 @SuppressWarnings("serial")
142 private class AllPlayCallbackException extends Exception {
144 public AllPlayCallbackException(String message) {