1 package org.rpi.providers;
2
3 import java.util.HashMap;
4 import java.util.Observable;
5 import java.util.Observer;
6 import java.util.concurrent.CopyOnWriteArrayList;
7
8 import org.apache.log4j.Logger;
9 import org.openhome.net.device.DvDevice;
10 import org.openhome.net.device.IDvInvocation;
11 import org.openhome.net.device.providers.DvProviderAvOpenhomeOrgPlaylist1;
12 import org.rpi.config.Config;
13 import org.rpi.player.CommandTracker;
14 import org.rpi.player.PlayManager;
15 import org.rpi.player.events.EventBase;
16 import org.rpi.player.events.EventPlayListPlayingTrackID;
17 import org.rpi.player.events.EventPlayListStatusChanged;
18 import org.rpi.player.events.EventPlayListUpdateShuffle;
19 import org.rpi.playlist.CustomTrack;
20 import org.rpi.playlist.PlayListReader;
21 import org.rpi.playlist.PlayListWriter;
22 import org.rpi.utils.Utils;
23
24 public class PrvPlayList extends DvProviderAvOpenhomeOrgPlaylist1 implements Observer {
25
26 private Logger log = Logger.getLogger(PrvPlayList.class);
27 private int next_id;
28 private PlayListWriter plw = null;
29 private int playlist_max = Config.playlist_max;
30 private CommandTracker tracker = new CommandTracker();
31
32 private CopyOnWriteArrayList<CustomTrack> tracks = new CopyOnWriteArrayList<CustomTrack>();
33
34 private PlayManager iPlayer = PlayManager.getInstance();
35
36 public PrvPlayList(DvDevice iDevice) {
37 super(iDevice);
38 log.debug("Creating CustomPlayList");
39
40 plw = new PlayListWriter();
41 plw.start();
42 enablePropertyTransportState();
43 enablePropertyRepeat();
44 enablePropertyShuffle();
45 enablePropertyId();
46 enablePropertyTracksMax();
47 enablePropertyProtocolInfo();
48 enablePropertyIdArray();
49
50 byte[] array = new byte[0];
51 setPropertyId(0);
52 setPropertyProtocolInfo(Config.getProtocolInfo());
53 setPropertyRepeat(false);
54 setPropertyShuffle(false);
55 setPropertyTracksMax(playlist_max);
56 setPropertyTransportState("");
57 setPropertyIdArray(array);
58
59 enableActionPlay();
60 enableActionPause();
61 enableActionStop();
62 enableActionNext();
63 enableActionPrevious();
64 enableActionSetRepeat();
65 enableActionRepeat();
66 enableActionSetShuffle();
67 enableActionShuffle();
68 enableActionSeekSecondAbsolute();
69 enableActionSeekSecondRelative();
70 enableActionSeekId();
71 enableActionSeekIndex();
72 enableActionTransportState();
73 enableActionId();
74 enableActionRead();
75 enableActionReadList();
76 enableActionInsert();
77 enableActionDeleteId();
78 enableActionDeleteAll();
79 enableActionTracksMax();
80 enableActionIdArray();
81 enableActionIdArrayChanged();
82 enableActionProtocolInfo();
83 PlayManager.getInstance().observPlayListEvents(this);
84 loadPlayList();
85 }
86
87 private void loadPlayList() {
88 if (Config.save_local_playlist) {
89 PlayListReader plr = new PlayListReader(this);
90 plr.getXML();
91 }
92 }
93
94 protected void pause(IDvInvocation paramIDvInvocation) {
95 log.debug("Pause" + Utils.getLogText(paramIDvInvocation));
96 iPlayer.pause(true);
97 };
98
99 protected void play(IDvInvocation paramIDvInvocation) {
100 log.debug("Play" + Utils.getLogText(paramIDvInvocation));
101 if (tracker.setRequest("PLAY")) {
102 iPlayer.play();
103 }
104 };
105
106 protected void stop(IDvInvocation paramIDvInvocation) {
107 log.debug("Stop" + Utils.getLogText(paramIDvInvocation));
108 iPlayer.stop();
109 };
110
111
112
113
114
115
116 public int getNext_id() {
117 next_id++;
118 log.debug("GetNextId: " + next_id);
119 return next_id;
120 }
121
122
123
124
125
126
127
128 public void setNextId(int max_id) {
129 next_id = max_id;
130
131 }
132
133 protected long insert(IDvInvocation paramIDvInvocation, long aAfterId, String aUri, String aMetaData) {
134 if (tracks.size() >= playlist_max) {
135 log.error("Maximum Size of PlayList Reached...");
136 return -1;
137 }
138 log.debug("Insert After: " + aAfterId + " URI: " + aUri + " MetaDate: \r\n" + aMetaData + Utils.getLogText(paramIDvInvocation));
139 int id = getNext_id();
140 CustomTrack track = new CustomTrack(aUri, aMetaData, id);
141 int iCount = 0;
142 if (aAfterId != 0) {
143 for (CustomTrack t : tracks) {
144 if (t.getId() == aAfterId) {
145 iCount++;
146 break;
147 }
148 iCount++;
149 }
150 }
151 try {
152 tracks.add(iCount, track);
153 } catch (Exception e) {
154 log.error("Error Adding Track: " + track.getId() + " After: " + aAfterId, e);
155 }
156 iPlayer.insertTrack(aAfterId, track);
157 UpdateIdArray();
158 log.debug("Insert Track Return: " + id);
159 return id;
160 };
161
162 protected void deleteAll(IDvInvocation paramIDvInvocation) {
163 log.debug("DeleteAll" + Utils.getLogText(paramIDvInvocation));
164 tracks.clear();
165 UpdateIdArray();
166 iPlayer.deleteAllTracks();
167 };
168
169 protected void deleteId(IDvInvocation paramIDvInvocation, long iD) {
170 log.debug("DeleteId: " + iD + Utils.getLogText(paramIDvInvocation));
171 int iCount = 0;
172 boolean found = false;
173 for (CustomTrack t : tracks) {
174 if (t.getId() == iD) {
175 found = true;
176 break;
177 }
178 iCount++;
179 }
180 if (found) {
181 try {
182 log.debug("Deleteing Id: " + iD + " at Position : " + iCount + " In List");
183 tracks.remove(iCount);
184 iPlayer.DeleteTrack(iD);
185 } catch (Exception e) {
186 log.error("Unable to Delete Track Id: " + iD + " At List Postion : " + iCount, e);
187 }
188 }
189 UpdateIdArray();
190 };
191
192 protected long id(IDvInvocation paramIDvInvocation) {
193 log.debug("GetId" + Utils.getLogText(paramIDvInvocation));
194 long id = getPropertyId();
195 return id;
196 };
197
198 protected String protocolInfo(IDvInvocation paramIDvInvocation) {
199 String protocolInfo = getPropertyProtocolInfo();
200 log.debug("GetProtocolInfo: \r\n" + protocolInfo + Utils.getLogText(paramIDvInvocation));
201 return protocolInfo;
202 };
203
204 protected IdArray idArray(IDvInvocation paramIDvInvocation) {
205 log.debug("GetIdArray" + Utils.getLogText(paramIDvInvocation));
206 byte[] array = getPropertyIdArray();
207 DvProviderAvOpenhomeOrgPlaylist1.IdArray idArray = new IdArray(0, array);
208 return idArray;
209 };
210
211 protected boolean idArrayChanged(IDvInvocation paramIDvInvocation, long paramLong) {
212 log.debug("GetIdArrayChanged" + Utils.getLogText(paramIDvInvocation));
213 boolean changed = false;
214 return changed;
215 };
216
217 protected void next(IDvInvocation paramIDvInvocation) {
218 log.debug("Next" + Utils.getLogText(paramIDvInvocation));
219 iPlayer.nextTrack();
220 };
221
222 protected void previous(IDvInvocation paramIDvInvocation) {
223 log.debug("Previous" + Utils.getLogText(paramIDvInvocation));
224 iPlayer.previousTrack();
225 };
226
227 protected Read read(IDvInvocation paramIDvInvocation, long paramLong) {
228 log.debug("Read Index: " + paramLong + Utils.getLogText(paramIDvInvocation));
229 try {
230 for (CustomTrack t : tracks) {
231 if (t.getId() == paramLong) {
232 DvProviderAvOpenhomeOrgPlaylist1.Read read = new Read(t.getUri(), t.getMetadata());
233 return read;
234 }
235 }
236 } catch (Exception e) {
237 log.error("Error read Index: " + paramLong, e);
238 }
239 DvProviderAvOpenhomeOrgPlaylist1.Read read = new Read("", "");
240 return read;
241 };
242
243 protected String readList(IDvInvocation paramIDvInvocation, String ids) {
244
245 log.debug("ReadList: " + ids + Utils.getLogText(paramIDvInvocation));
246 return getList(ids);
247 };
248
249 protected boolean repeat(IDvInvocation paramIDvInvocation) {
250 boolean repeat = getPropertyRepeat();
251 log.debug("Repeat: " + repeat + Utils.getLogText(paramIDvInvocation));
252 return repeat;
253 };
254
255 protected void seekId(IDvInvocation paramIDvInvocation, long id) {
256 log.debug("SeekId: " + id + Utils.getLogText(paramIDvInvocation));
257 tracker.setRequest("SEEKID");
258 iPlayer.playTrackId(id);
259 };
260
261 protected void seekIndex(IDvInvocation paramIDvInvocation, long id) {
262 log.debug("SeekIndex: " + id + Utils.getLogText(paramIDvInvocation));
263 tracker.setRequest("SEEKINDEX");
264 iPlayer.playIndex(id);
265 };
266
267 protected void seekSecondAbsolute(IDvInvocation paramIDvInvocation, long seconds) {
268 log.debug("SeekSecondAbsolute: " + seconds + Utils.getLogText(paramIDvInvocation));
269 iPlayer.seekAbsolute(seconds);
270 };
271
272 protected void seekSecondRelative(IDvInvocation paramIDvInvocation, int paramInt) {
273 log.debug("SeekSecondRelative: " + paramInt + Utils.getLogText(paramIDvInvocation));
274 };
275
276 protected void setRepeat(IDvInvocation paramIDvInvocation, boolean repeat) {
277 log.debug("SetRepeat: " + repeat + Utils.getLogText(paramIDvInvocation));
278 setPropertyRepeat(repeat);
279 iPlayer.setRepeatPlayList(repeat);
280 };
281
282 protected void setShuffle(IDvInvocation paramIDvInvocation, boolean paramBoolean) {
283 log.debug("SetShuffle: " + paramBoolean + Utils.getLogText(paramIDvInvocation));
284 setPropertyShuffle(paramBoolean);
285 iPlayer.setShuffle(paramBoolean);
286 };
287
288 protected boolean shuffle(IDvInvocation paramIDvInvocation) {
289 boolean shuffle = getPropertyShuffle();
290 log.debug("GetShuffle: " + shuffle + Utils.getLogText(paramIDvInvocation));
291 return shuffle;
292 };
293
294 protected long tracksMax(IDvInvocation paramIDvInvocation) {
295 long tracksMax = getPropertyTracksMax();
296 log.debug("GetTracksMax: " + tracksMax + Utils.getLogText(paramIDvInvocation));
297 return tracksMax;
298 };
299
300 protected String transportState(IDvInvocation paramIDvInvocation) {
301 String state = getPropertyTransportState();
302 log.debug("TransportState: " + state + Utils.getLogText(paramIDvInvocation));
303 return state;
304 };
305
306 private synchronized void UpdateIdArray(boolean bUpdateFile) {
307 int size = tracks.size() * 4;
308 StringBuilder sb = new StringBuilder();
309 byte[] bytes = new byte[size];
310 for (CustomTrack t : tracks) {
311 try {
312 int intValue = (int) t.getId();
313 String binValue = Integer.toBinaryString(intValue);
314 binValue = padLeft(binValue, 32, '0');
315 sb.append(binValue);
316 } catch (Exception e) {
317 log.error(e);
318 }
319 }
320
321
322 String myBytes = sb.toString();
323 int numOfBytes = myBytes.length() / 8;
324 bytes = new byte[numOfBytes];
325 try
326
327 {
328 for (int i = 0; i < numOfBytes; ++i) {
329 int index = 8 * i;
330 String sByte = myBytes.substring(index, index + 8);
331
332
333 Integer x = Integer.parseInt(sByte, 2);
334 Byte sens = (byte) x.intValue();
335
336 bytes[i] = sens;
337
338
339
340
341 }
342
343 setPropertyIdArray(bytes);
344 if (bUpdateFile) {
345 plw.trigger(tracks);
346 }
347 } catch (Exception e) {
348 log.error("Error Writing Bytes: " + sb.toString(), e);
349 }
350
351 }
352
353
354
355
356
357
358 private synchronized void UpdateIdArray() {
359 UpdateIdArray(true);
360 }
361
362 private String padLeft(String str, int length, char padChar) {
363 StringBuilder sb = new StringBuilder();
364
365 for (int toPrepend = length - str.length(); toPrepend > 0; toPrepend--) {
366 sb.append(padChar);
367 }
368 sb.append(str);
369 return sb.toString();
370 }
371
372
373
374
375
376
377 private void playingTrack(int iD) {
378 setPropertyId(iD);
379 }
380
381 public synchronized void setTracks(CopyOnWriteArrayList<CustomTrack> tracks) {
382 this.tracks = tracks;
383 iPlayer.setTracks(tracks);
384 UpdateIdArray(false);
385 }
386
387 public void setStatus(String status) {
388 setPropertyTransportState(status);
389 }
390
391 private String getList(String ids) {
392 int i = 0;
393 HashMap<String, String> trackIds = new HashMap<String,String>();
394 for(String key:ids.split(" "))
395 {
396 trackIds.put(key, key);
397 }
398 StringBuilder sb = new StringBuilder();
399 sb.append("<TrackList>");
400 for (CustomTrack t : tracks) {
401 if (trackIds.containsKey("" + t.getId())) {
402 i++;
403 sb.append(t.getFullText());
404 }
405 }
406 sb.append("</TrackList>");
407 log.debug("ReadList Contains : " + i + " " + sb.toString());
408 return sb.toString();
409 }
410
411 @Override
412 public void dispose() {
413 plw = null;
414 super.dispose();
415 }
416
417 public void updateShuffle(boolean shuffle) {
418 setPropertyShuffle(shuffle);
419 }
420
421 @Override
422 public void update(Observable o, Object arg) {
423 EventBase e = (EventBase) arg;
424 switch (e.getType()) {
425
426 case EVENTPLAYLISTSTATUSCHANGED:
427 EventPlayListStatusChanged ers = (EventPlayListStatusChanged) e;
428 setStatus(ers.getStatus());
429 break;
430
431 case EVENTPLAYLISTPLAYINGTRACKID:
432 EventPlayListPlayingTrackID eri = (EventPlayListPlayingTrackID) e;
433 playingTrack(eri.getId());
434 break;
435
436 case EVENTPLAYLISTUPDATESHUFFLE:
437 EventPlayListUpdateShuffle eps = (EventPlayListUpdateShuffle) e;
438 updateShuffle(eps.isShuffle());
439 break;
440
441 }
442
443 }
444
445 }