]> git.basschouten.com Git - openhab-addons.git/blob
7ead4a125887a07752de15fd86665706f2df3c9d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.squeezebox.internal;
14
15 import java.util.HashSet;
16 import java.util.Locale;
17 import java.util.Set;
18
19 import org.openhab.binding.squeezebox.internal.handler.SqueezeBoxPlayerHandler;
20 import org.openhab.core.audio.AudioFormat;
21 import org.openhab.core.audio.AudioHTTPServer;
22 import org.openhab.core.audio.AudioSink;
23 import org.openhab.core.audio.AudioStream;
24 import org.openhab.core.audio.FileAudioStream;
25 import org.openhab.core.audio.FixedLengthAudioStream;
26 import org.openhab.core.audio.URLAudioStream;
27 import org.openhab.core.audio.UnsupportedAudioFormatException;
28 import org.openhab.core.audio.UnsupportedAudioStreamException;
29 import org.openhab.core.audio.utils.AudioStreamUtils;
30 import org.openhab.core.library.types.PercentType;
31 import org.openhab.core.library.types.StringType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * This makes a SqueezeBox Player serve as an {@link AudioSink}-
37  *
38  * @author Mark Hilbush - Initial contribution
39  * @author Mark Hilbush - Add callbackUrl
40  */
41 public class SqueezeBoxAudioSink implements AudioSink {
42     private final Logger logger = LoggerFactory.getLogger(SqueezeBoxAudioSink.class);
43
44     private static final HashSet<AudioFormat> SUPPORTED_FORMATS = new HashSet<>();
45     private static final HashSet<Class<? extends AudioStream>> SUPPORTED_STREAMS = new HashSet<>();
46
47     // Needed because Squeezebox does multiple requests for the stream
48     private static final int STREAM_TIMEOUT = 15;
49
50     private String callbackUrl;
51
52     static {
53         SUPPORTED_FORMATS.add(AudioFormat.WAV);
54         SUPPORTED_FORMATS.add(AudioFormat.MP3);
55
56         SUPPORTED_STREAMS.add(FixedLengthAudioStream.class);
57         SUPPORTED_STREAMS.add(URLAudioStream.class);
58     }
59
60     private AudioHTTPServer audioHTTPServer;
61     private SqueezeBoxPlayerHandler playerHandler;
62
63     public SqueezeBoxAudioSink(SqueezeBoxPlayerHandler playerHandler, AudioHTTPServer audioHTTPServer,
64             String callbackUrl) {
65         this.playerHandler = playerHandler;
66         this.audioHTTPServer = audioHTTPServer;
67         this.callbackUrl = callbackUrl;
68         if (callbackUrl != null && !callbackUrl.isEmpty()) {
69             logger.debug("SqueezeBox AudioSink created with callback URL: {}", callbackUrl);
70         }
71     }
72
73     @Override
74     public String getId() {
75         return playerHandler.getThing().getUID().toString();
76     }
77
78     @Override
79     public String getLabel(Locale locale) {
80         return playerHandler.getThing().getLabel();
81     }
82
83     @Override
84     public void process(AudioStream audioStream)
85             throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
86         AudioFormat format = audioStream.getFormat();
87         if (!AudioFormat.WAV.isCompatible(format) && !AudioFormat.MP3.isCompatible(format)) {
88             throw new UnsupportedAudioFormatException("Currently only MP3 and WAV formats are supported: ", format);
89         }
90
91         String url;
92         if (audioStream instanceof URLAudioStream) {
93             url = ((URLAudioStream) audioStream).getURL();
94         } else if (audioStream instanceof FixedLengthAudioStream) {
95             // Since Squeezebox will make multiple requests for the stream, set a timeout on the stream
96             url = audioHTTPServer.serve((FixedLengthAudioStream) audioStream, STREAM_TIMEOUT).toString();
97
98             if (AudioFormat.WAV.isCompatible(format)) {
99                 url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.WAV_EXTENSION;
100             } else if (AudioFormat.MP3.isCompatible(format)) {
101                 url += AudioStreamUtils.EXTENSION_SEPARATOR + FileAudioStream.MP3_EXTENSION;
102             }
103
104             // Form the URL for streaming the notification from the OH2 web server
105             // Use the callback URL if it is set in the binding configuration
106             String host = callbackUrl == null || callbackUrl.isEmpty() ? playerHandler.getHostAndPort() : callbackUrl;
107             if (host == null) {
108                 logger.warn("Unable to get host/port from which to stream notification");
109                 return;
110             }
111             url = host + url;
112         } else {
113             throw new UnsupportedAudioStreamException(
114                     "SqueezeBox can only handle URLAudioStream or FixedLengthAudioStreams.", null);
115         }
116
117         logger.debug("Processing audioStream {} of format {}", url, format);
118         playerHandler.playNotificationSoundURI(new StringType(url));
119     }
120
121     @Override
122     public Set<AudioFormat> getSupportedFormats() {
123         return SUPPORTED_FORMATS;
124     }
125
126     @Override
127     public Set<Class<? extends AudioStream>> getSupportedStreams() {
128         return SUPPORTED_STREAMS;
129     }
130
131     @Override
132     public PercentType getVolume() {
133         return playerHandler.getNotificationSoundVolume();
134     }
135
136     @Override
137     public void setVolume(PercentType volume) {
138         playerHandler.setNotificationSoundVolume(volume);
139     }
140 }