]> git.basschouten.com Git - openhab-addons.git/blob
bb8fe0d28e392fe7a6400843574760c3b55f08fd
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.allplay.internal;
14
15 import java.io.IOException;
16 import java.util.HashSet;
17 import java.util.Locale;
18 import java.util.Set;
19
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;
31
32 import de.kaizencode.tchaikovsky.exception.SpeakerException;
33
34 /**
35  * The {@link AllPlayAudioSink} make AllPlay speakers available as an {@link AudioSink}.
36  *
37  * @author Dominic Lerbs - Initial contribution
38  */
39 public class AllPlayAudioSink implements AudioSink {
40
41     private final Logger logger = LoggerFactory.getLogger(AllPlayAudioSink.class);
42
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;
48
49     static {
50         SUPPORTED_FORMATS.add(AudioFormat.MP3);
51         SUPPORTED_FORMATS.add(AudioFormat.WAV);
52
53         SUPPORTED_STREAMS.add(AudioStream.class);
54     }
55
56     /**
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
60      */
61     public AllPlayAudioSink(AllPlayHandler handler, AudioHTTPServer audioHTTPServer, String callbackUrl) {
62         this.handler = handler;
63         this.audioHTTPServer = audioHTTPServer;
64         this.callbackUrl = callbackUrl;
65     }
66
67     @Override
68     public String getId() {
69         return handler.getThing().getUID().toString();
70     }
71
72     @Override
73     public String getLabel(Locale locale) {
74         return handler.getThing().getLabel();
75     }
76
77     @Override
78     public void process(AudioStream audioStream)
79             throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
80         try {
81             String url = convertAudioStreamToUrl(audioStream);
82             handler.playUrl(url);
83         } catch (SpeakerException | AllPlayCallbackException e) {
84             logger.warn("Unable to play audio stream on speaker {}", getId(), e);
85         }
86     }
87
88     @Override
89     public Set<AudioFormat> getSupportedFormats() {
90         return SUPPORTED_FORMATS;
91     }
92
93     @Override
94     public Set<Class<? extends AudioStream>> getSupportedStreams() {
95         return SUPPORTED_STREAMS;
96     }
97
98     @Override
99     public PercentType getVolume() throws IOException {
100         try {
101             return handler.getVolume();
102         } catch (SpeakerException e) {
103             throw new IOException(e);
104         }
105     }
106
107     @Override
108     public void setVolume(PercentType volume) throws IOException {
109         try {
110             handler.handleVolumeCommand(volume);
111         } catch (SpeakerException e) {
112             throw new IOException(e);
113         }
114     }
115
116     /**
117      * Converts the given {@link AudioStream} into an URL which can be used for streaming.
118      *
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
122      */
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();
127         } else {
128             return createUrlForLocalHttpServer(audioStream);
129         }
130     }
131
132     private String createUrlForLocalHttpServer(AudioStream audioStream) throws AllPlayCallbackException {
133         if (callbackUrl != null) {
134             String relativeUrl = audioHTTPServer.serve(audioStream);
135             return callbackUrl + relativeUrl;
136         } else {
137             throw new AllPlayCallbackException("Unable to play audio stream as callback URL is not set");
138         }
139     }
140
141     @SuppressWarnings("serial")
142     private class AllPlayCallbackException extends Exception {
143
144         public AllPlayCallbackException(String message) {
145             super(message);
146         }
147     }
148 }