View Javadoc

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 	 * Returns the track Id
113 	 * 
114 	 * @return
115 	 */
116 	public int getNext_id() {
117 		next_id++;
118 		log.debug("GetNextId: " + next_id);
119 		return next_id;
120 	}
121 
122 	/***
123 	 * If reading the playList from the xml file, make sure that the nextId is
124 	 * set to the max_id of the .xml entry..
125 	 * 
126 	 * @param max_id
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 		// Now we have a big long string of binary, chop it up and get the
321 		// bytes for the byte array..
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 				// try {
332 				// log.debug("Byte: " + sByte);
333 				Integer x = Integer.parseInt(sByte, 2);
334 				Byte sens = (byte) x.intValue();
335 				// byte b = Byte.parseByte(sByte, 2);
336 				bytes[i] = sens;
337 				// } catch (Exception e) {
338 				// log.error("Error parseByte: " + sByte , e);
339 				// }
340 
341 			}
342 			//log.debug("UpdateIdArray: " + sb.toString());
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 	 * Itarate all tracks, and create a 32 bit binary number from the track Id.
355 	 * Add the 32 bit binary string to a long string Split the 32 bit binary
356 	 * long string 4 bytes (8bits) And add to a byte array
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 	// private boolean PauseTrack() {
373 	// iPlayer.pause(true);
374 	// return true;
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 }