]> git.basschouten.com Git - openhab-addons.git/blob
1043d9a73c488cdc460a87e14778becc502d732a
[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.mpd.internal.protocol;
14
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.openhab.binding.mpd.internal.handler.MPDEventListener;
18 import org.openhab.core.thing.ThingStatus;
19 import org.openhab.core.thing.ThingStatusDetail;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /**
24  * Class for communicating with the music player daemon through an IP connection
25  *
26  * @author Stefan Röllin - Initial contribution
27  */
28 @NonNullByDefault
29 public class MPDConnection implements MPDResponseListener {
30
31     private static final int DISPOSE_TIMEOUT_MS = 1000;
32
33     private final Logger logger = LoggerFactory.getLogger(MPDConnection.class);
34
35     private final MPDEventListener listener;
36
37     private @Nullable MPDConnectionThread connectionThread = null;
38
39     /**
40      * Constructor
41      *
42      * @param address the IP address of the music player daemon
43      * @param port the TCP port to be used
44      * @param password the password to connect to the music player daemon
45      */
46     public MPDConnection(MPDEventListener listener) {
47         this.listener = listener;
48     }
49
50     /**
51      * start the connection
52      *
53      * @param address the IP address of the music player daemon
54      * @param port the TCP port to be used
55      * @param password the password to connect to the music player daemon
56      * @param threadName the name of the thread
57      */
58     public void start(String address, Integer port, String password, String threadName) {
59         if (connectionThread == null) {
60             final MPDConnectionThread connectionThread = new MPDConnectionThread(this, address, port, password);
61             connectionThread.setName(threadName);
62             connectionThread.start();
63             this.connectionThread = connectionThread;
64         }
65     }
66
67     /**
68      * dispose the connection
69      */
70     public void dispose() {
71         final MPDConnectionThread connectionThread = this.connectionThread;
72         if (connectionThread != null) {
73             connectionThread.dispose();
74             connectionThread.interrupt();
75             try {
76                 connectionThread.join(DISPOSE_TIMEOUT_MS);
77             } catch (InterruptedException ignore) {
78             }
79             this.connectionThread = null;
80         }
81     }
82
83     /**
84      * send a command to the music player daemon
85      *
86      * @param command command to send
87      * @param parameter parameter of command
88      */
89     public void sendCommand(String command, String... parameter) {
90         addCommand(new MPDCommand(command, parameter));
91     }
92
93     /**
94      * play
95      */
96     public void play() {
97         sendCommand("play");
98     }
99
100     /**
101      * pause the music player daemon
102      */
103     public void pause() {
104         addCommand(new MPDCommand("pause", 1));
105     }
106
107     /**
108      * play next track
109      */
110     public void playNext() {
111         sendCommand("next");
112     }
113
114     /**
115      * play previous track
116      */
117     public void playPrevious() {
118         sendCommand("previous");
119     }
120
121     /**
122      * stop the music player daemon
123      */
124     public void stop() {
125         sendCommand("stop");
126     }
127
128     /**
129      * update status
130      */
131     public void updateStatus() {
132         sendCommand("status");
133     }
134
135     /**
136      * update information regarding current song
137      */
138     public void updateCurrentSong() {
139         sendCommand("currentsong");
140     }
141
142     /**
143      * set volume
144      *
145      * @param volume set new volume
146      */
147     public void setVolume(int volume) {
148         addCommand(new MPDCommand("setvol", volume));
149     }
150
151     private void addCommand(MPDCommand command) {
152         MPDConnectionThread connectionThread = this.connectionThread;
153         if (connectionThread != null) {
154             connectionThread.addCommand(command);
155         } else {
156             logger.debug("could not add command {} since thing offline", command.getCommand());
157         }
158     }
159
160     @Override
161     public void updateThingStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String cause) {
162         listener.updateThingStatus(status, statusDetail, cause);
163     }
164
165     @Override
166     public void onResponse(MPDResponse response) {
167         switch (response.getCommand()) {
168             case "idle":
169                 handleResponseIdle(response);
170                 break;
171             case "status":
172                 handleResponseStatus(response);
173                 break;
174             case "currentsong":
175                 handleResponseCurrentSong(response);
176                 break;
177             default:
178                 break;
179         }
180     }
181
182     private void handleResponseCurrentSong(MPDResponse response) {
183         MPDSong song = new MPDSong(response);
184         listener.updateMPDSong(song);
185     }
186
187     private void handleResponseIdle(MPDResponse response) {
188         boolean updateStatus = false;
189         boolean updateCurrentSong = false;
190         for (String line : response.getLines()) {
191             if (line.startsWith("changed:")) {
192                 line = line.substring(8).trim();
193                 switch (line) {
194                     case "player":
195                         updateStatus = true;
196                         updateCurrentSong = true;
197                         break;
198                     case "mixer":
199                         updateStatus = true;
200                         break;
201                     case "playlist":
202                         updateCurrentSong = true;
203                         break;
204                 }
205             }
206         }
207
208         if (updateStatus) {
209             updateStatus();
210         }
211         if (updateCurrentSong) {
212             updateCurrentSong();
213         }
214     }
215
216     private void handleResponseStatus(MPDResponse response) {
217         MPDStatus song = new MPDStatus(response);
218         listener.updateMPDStatus(song);
219     }
220 }