1 package org.rpi.mplayer;
2
3 import java.io.IOException;
4 import java.lang.Thread.State;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Observable;
8 import java.util.Observer;
9
10 import org.apache.log4j.Logger;
11 import org.rpi.config.Config;
12 import org.rpi.player.IPlayer;
13 import org.rpi.player.events.EventBase;
14 import org.rpi.player.events.EventFinishedCurrentTrack;
15 import org.rpi.player.events.EventStatusChanged;
16 import org.rpi.player.events.EventUpdateTrackMetaText;
17 import org.rpi.playlist.CustomTrack;
18
19 public class MPlayer extends Observable implements IPlayer, Observer {
20
21 private Logger log = Logger.getLogger(MPlayer.class);
22 private Process process = null;
23 private OutputReader reader = null;
24 private InputWriter writer = null;
25 private PositionThread position = null;
26
27 private boolean bPaused = false;
28 private boolean bPlaying = false;
29
30
31 private boolean bLoading = false;
32
33 private TrackInfo trackInfo = null;
34 private long volume = 100;
35
36 private String uniqueId = "";
37
38 private CustomTrack current_track = null;
39 private boolean bMute;
40
41 private boolean mute = false;
42
43
44
45
46
47
48
49 public boolean playTrack(CustomTrack track, long volume, boolean mute) {
50 uniqueId = track.getUniqueId();
51 this.volume = volume;
52 this.bMute = mute;
53 current_track = track;
54 log.info("Starting to playTrack Id: " + uniqueId + " " + track.getFullDetails());
55 String url = track.getUri();
56 try {
57 initProcess(url);
58 } catch (Exception e) {
59 log.error("Error playTrack: ", e);
60 }
61 return true;
62 }
63
64
65
66
67 public void preLoadTrack(CustomTrack track) {
68 }
69
70
71
72
73 public void startTrack() {
74 startPlaying();
75 }
76
77
78
79
80
81
82 public void openFile(CustomTrack t) {
83 }
84
85 public synchronized void startPlaying() {
86 log.debug("Starting to Play: " + uniqueId);
87 setVolume(volume);
88 if (bMute) {
89 setMute(bMute);
90 }
91 log.debug("Started to Play: " + uniqueId);
92 setStatus("Playing");
93 setPlaying(true);
94 bLoading = false;
95 bPaused = false;
96 log.debug("PositionThreadState: " + position.getState());
97 if (position.getState() == State.NEW) {
98 log.debug("Position Thread is in State NEW Start Thread");
99 position.start();
100 }
101 }
102
103 public synchronized void loaded() {
104 }
105
106 public synchronized void playingTrack() {
107 startPlaying();
108 }
109
110
111
112
113
114
115
116
117 private void initProcess(String url) throws IOException {
118 try {
119 List<String> params = new ArrayList<String>();
120 params.add(Config.mplayer_path);
121 params.add("-slave");
122 params.add("-quiet");
123 if (Config.mplayer_cache > 0) {
124 params.add("-cache");
125 params.add("" + Config.mplayer_cache);
126 }
127 if (Config.mplayer_cache_min > 0) {
128 params.add("-cache-min");
129 params.add("" + Config.mplayer_cache_min);
130 }
131
132 trackInfo = new TrackInfo();
133 trackInfo.addObserver(this);
134 if (isPlayList(url)) {
135 params.add("-playlist");
136 }
137 params.add(url);
138 ProcessBuilder builder = new ProcessBuilder(params);
139 builder.redirectErrorStream(true);
140 process = builder.start();
141 log.debug("Create new InputWriter");
142 writer = new InputWriter(process);
143 log.debug("Create new OutputReader");
144 reader = new OutputReader(this);
145 log.debug("Create new Position Thread");
146 position = new PositionThread(this);
147 log.debug("Create new Position Thread");
148 position.setNewTrack(true);
149 reader.start();
150 } catch (Exception e) {
151 log.error("Error initProcess: ", e);
152 }
153 }
154
155
156
157
158
159
160
161 private boolean isPlayList(String url) {
162 for (String s : Config.playlists) {
163 if (url.toLowerCase().contains(s.toLowerCase())) {
164 return true;
165 }
166 }
167 return false;
168 }
169
170 @Override
171 public void pause(boolean bPause) {
172 bPaused = true;
173 log.debug("Sending: pause");
174 sendCommand("pause");
175 EventStatusChanged ev = new EventStatusChanged();
176 ev.setStatus("Paused");
177 fireEvent(ev);
178 }
179
180 @Override
181 public synchronized void stop() {
182 log.debug("Sending: quit");
183 sendCommand("quit");
184 EventStatusChanged ev = new EventStatusChanged();
185 ev.setStatus("Stopped");
186 fireEvent(ev);
187 }
188
189 @Override
190 public synchronized void destroy() {
191 log.debug("Attempting to Stop MPlayer");
192 sendCommand("quit");
193 reader = null;
194 writer = null;
195 if (position != null) {
196 position.interrupt();
197 position = null;
198 }
199 }
200
201 public synchronized InputWriter getCommandWriter() {
202 return writer;
203 }
204
205
206
207
208 public boolean isbPaused() {
209 return bPaused;
210 }
211
212
213
214
215 public boolean isPlaying() {
216 if (process != null) {
217 if (position != null) {
218 return true;
219 }
220 }
221 return false;
222 }
223
224
225
226
227
228 public void setPlaying(boolean bPlaying) {
229 log.debug("setPlaying: " + bPlaying);
230 this.bPlaying = bPlaying;
231 }
232
233
234
235
236 public synchronized void stoppedPlaying() {
237 writer.setStopSendingCommands(true);
238 log.debug("Stopped Playing get next track: ");
239 setPlaying(false);
240 setStatus("Stopped");
241 position.interrupt();
242 position = null;
243 reader = null;
244 EventFinishedCurrentTrack ev = new EventFinishedCurrentTrack();
245 fireEvent(ev);
246 }
247
248
249
250
251
252
253 public synchronized void setStatus(String status) {
254 EventStatusChanged ev = new EventStatusChanged();
255 ev.setStatus(status);
256 ev.setTrack(current_track);
257 fireEvent(ev);
258 }
259
260 public synchronized Process getProcess() {
261 return this.process;
262 }
263
264
265
266
267 public synchronized TrackInfo getTrackInfo() {
268 return trackInfo;
269 }
270
271 @Override
272 public void setMute(boolean mute) {
273 this.mute = mute;
274 if (mute) {
275 sendCommand("pausing_keep mute");
276
277
278 } else {
279 sendCommand("pausing_keep mute");
280
281 sendCommand("pausing_keep volume " + (volume - 1) + " 1");
282 setVolume(volume);
283 }
284 }
285
286 @Override
287 public void setVolume(long volume) {
288 this.volume = volume;
289 if(!mute)
290 sendCommand("pausing_keep volume " + volume + " 1");
291 }
292
293 @Override
294 public void seekAbsolute(long seconds) {
295 sendCommand("seek " + seconds + " 2");
296 }
297
298
299
300
301
302
303
304 public synchronized void updateInfo(String artist, String title) {
305 EventUpdateTrackMetaText ev = new EventUpdateTrackMetaText();
306 ev.setArtist(artist);
307 ev.setTitle(title);
308 fireEvent(ev);
309 }
310
311
312
313
314 public void endPositionThread() {
315 if (position != null) {
316 try {
317 position.interrupt();
318 } catch (Exception e) {
319 log.error("Error Stopping Position Thread", e);
320 }
321 }
322 }
323
324
325
326
327 @Override
328 public synchronized void resume() {
329 bPaused = false;
330 sendCommand("pause");
331 EventStatusChanged ev = new EventStatusChanged();
332 ev.setStatus("Playing");
333 fireEvent(ev);
334 }
335
336
337
338
339
340
341 public synchronized void sendCommand(String command) {
342 if (writer != null) {
343 log.debug("Sending: " + command + " TrackId: " + uniqueId);
344 writer.sendCommand(command);
345 log.debug("Sent: " + command + " TrackId: " + uniqueId);
346 } else {
347 log.info("Could Not Send Command, Writer was null: " + command);
348 }
349 }
350
351 public synchronized void fireEvent(EventBase ev) {
352 setChanged();
353 notifyObservers(ev);
354 }
355
356 public boolean isLoading() {
357 return bLoading;
358 }
359
360 @Override
361 public String getUniqueId() {
362 return uniqueId;
363 }
364
365 @Override
366 public String toString() {
367 StringBuilder sb = new StringBuilder();
368 sb.append("UniqueId: " + uniqueId);
369 sb.append("Writer: " + writer.toString());
370 sb.append("Reader: " + reader.toString());
371 return sb.toString();
372 }
373
374 @Override
375 public void update(Observable o, Object evt) {
376 EventBase e = (EventBase)evt;
377 fireEvent(e);
378 }
379
380
381 }