2 * Copyright (c) 2010-2023 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.upnpcontrol.internal.audiosink;
15 import java.io.IOException;
16 import java.util.Locale;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.upnpcontrol.internal.handler.UpnpRendererHandler;
22 import org.openhab.core.audio.AudioFormat;
23 import org.openhab.core.audio.AudioHTTPServer;
24 import org.openhab.core.audio.AudioSinkAsync;
25 import org.openhab.core.audio.AudioStream;
26 import org.openhab.core.audio.StreamServed;
27 import org.openhab.core.audio.URLAudioStream;
28 import org.openhab.core.audio.UnsupportedAudioFormatException;
29 import org.openhab.core.audio.UnsupportedAudioStreamException;
30 import org.openhab.core.library.types.PercentType;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
36 * @author Mark Herwege - Initial contribution
37 * @author Laurent Garnier - Support for more audio streams through the HTTP audio servlet
40 public class UpnpAudioSink extends AudioSinkAsync {
42 private final Logger logger = LoggerFactory.getLogger(UpnpAudioSink.class);
44 private static final Set<Class<? extends AudioStream>> SUPPORTED_STREAMS = Set.of(AudioStream.class);
45 protected UpnpRendererHandler handler;
46 protected AudioHTTPServer audioHTTPServer;
47 protected String callbackUrl;
49 public UpnpAudioSink(UpnpRendererHandler handler, AudioHTTPServer audioHTTPServer, String callbackUrl) {
50 this.handler = handler;
51 this.audioHTTPServer = audioHTTPServer;
52 this.callbackUrl = callbackUrl;
56 public String getId() {
57 return handler.getThing().getUID().toString();
61 public @Nullable String getLabel(@Nullable Locale locale) {
62 return handler.getThing().getLabel();
66 protected void processAsynchronously(@Nullable AudioStream audioStream)
67 throws UnsupportedAudioFormatException, UnsupportedAudioStreamException {
68 if (audioStream == null) {
73 if (audioStream instanceof URLAudioStream urlAudioStream) {
74 playMedia(urlAudioStream.getURL());
77 } catch (IOException e) {
79 } else if (!callbackUrl.isEmpty()) {
80 StreamServed streamServed;
82 streamServed = audioHTTPServer.serve(audioStream, 5, true);
83 } catch (IOException e) {
86 } catch (IOException ex) {
88 throw new UnsupportedAudioStreamException(
89 handler.getUDN() + " was not able to handle the audio stream (cache on disk failed).",
90 audioStream.getClass(), e);
92 streamServed.playEnd().thenRun(() -> this.playbackFinished(audioStream));
93 playMedia(callbackUrl + streamServed.url());
95 logger.warn("We do not have any callback url, so {} cannot play the audio stream!", handler.getUDN());
98 } catch (IOException e) {
104 public Set<AudioFormat> getSupportedFormats() {
105 return handler.getSupportedAudioFormats();
109 public Set<Class<? extends AudioStream>> getSupportedStreams() {
110 return SUPPORTED_STREAMS;
114 public PercentType getVolume() throws IOException {
115 return handler.getCurrentVolume();
119 public void setVolume(@Nullable PercentType volume) throws IOException {
120 if (volume != null) {
121 handler.setVolume(volume);
125 protected void stopMedia() {
129 protected void playMedia(String url) {
131 if (!url.startsWith("x-") && !url.startsWith("http")) {
132 newUrl = "x-file-cifs:" + url;
134 handler.setCurrentURI(newUrl, "");