View Javadoc

1   package org.rpi.player;
2   
3   import java.util.Collections;
4   import java.util.Observable;
5   import java.util.Observer;
6   import java.util.Random;
7   import java.util.concurrent.CopyOnWriteArrayList;
8   
9   import org.apache.log4j.Logger;
10  import org.rpi.config.Config;
11  import org.rpi.mpdplayer.MPDPlayerController;
12  import org.rpi.mplayer.MPlayerController;
13  import org.rpi.player.events.EventBase;
14  import org.rpi.player.events.EventFinishedCurrentTrack;
15  import org.rpi.player.events.EventMuteChanged;
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.player.events.EventRadioPlayName;
20  import org.rpi.player.events.EventRadioPlayingTrackID;
21  import org.rpi.player.events.EventRadioStatusChanged;
22  import org.rpi.player.events.EventRequestVolumeDec;
23  import org.rpi.player.events.EventRequestVolumeInc;
24  import org.rpi.player.events.EventStandbyChanged;
25  import org.rpi.player.events.EventStatusChanged;
26  import org.rpi.player.events.EventTimeUpdate;
27  import org.rpi.player.events.EventTrackChanged;
28  import org.rpi.player.events.EventUpdateTrackMetaText;
29  import org.rpi.player.events.EventVolumeChanged;
30  import org.rpi.player.observers.*;
31  import org.rpi.player.observers.ObservableTime;
32  import org.rpi.playlist.CustomTrack;
33  import org.rpi.radio.CustomChannel;
34  //import org.rpi.mplayer.MPlayer;
35  //import org.rpi.player.IPlayer;
36  
37  public class PlayManager implements Observer {
38  
39  	private CustomTrack current_track = null;
40  	private CopyOnWriteArrayList<CustomTrack> tracks = new CopyOnWriteArrayList<CustomTrack>();
41  	private CopyOnWriteArrayList<String> shuffled_tracks = new CopyOnWriteArrayList<String>();
42  
43  	private static Logger log = Logger.getLogger(PlayManager.class);
44  	private IPlayerController mPlayer = null;
45  
46  	private boolean repeatPlayList = false;
47  	private boolean shuffle = false;
48  	private boolean bPaused;
49  	private boolean standby = true;
50  
51  	// For Volume
52  	private long volume = 100;
53  	private long mplayer_volume = 100;
54  	private boolean bMute;
55  	private boolean bExternalVolume = false;
56  
57  	// Observable Classes
58  	private ObservableTime obsvTime = new ObservableTime();
59  	private ObservableInfo obsvInfo = new ObservableInfo();
60  	private ObservableVolume obsvVolume = new ObservableVolume();
61  	private ObservableRadio obsvRadio = new ObservableRadio();
62  	private ObservablePlayList obsvPlayList = new ObservablePlayList();
63  	private ObservableProduct obsvProduct = new ObservableProduct();
64  	private ObservableAVTransport obsvAVTransport = new ObservableAVTransport();
65  	private String status = "";
66  
67  	private static PlayManager instance = null;
68  
69  	/**
70  	 * SingleInstance of the PlayManager
71  	 * 
72  	 * @return
73  	 */
74  	public static PlayManager getInstance() {
75  		if (instance == null) {
76  			instance = new PlayManager();
77  		}
78  		return instance;
79  	}
80  
81  	/**
82  	 * 
83  	 */
84  	private PlayManager() {
85  		if (Config.player.equalsIgnoreCase("MPD")) {
86  			log.debug("MPD Player Selected");
87  			mPlayer = new MPDPlayerController();
88  		} else {
89  			log.debug("MPlayer Selected");
90  			mPlayer = new MPlayerController();
91  		}
92  		mPlayer.addObserver(this);
93  	}
94  
95  	/**
96  	 * Play This Track If MPlayer is already running destroy it
97  	 * 
98  	 * @param t
99  	 */
100 	private void playThis(CustomTrack t) {
101 		if (t != null) {
102 			current_track = t;
103 			long v = mplayer_volume;
104 			if (!isUseExternalVolume())
105 				v = volume;
106 			mPlayer.playThis(t, v, bMute);
107 		}
108 	}
109 
110 	/**
111 	 * Get the Next Track when not in shuffle Mode
112 	 * 
113 	 * @param offset
114 	 * @return
115 	 */
116 	public CustomTrack getNextTrack(int offset) {
117 		if (shuffle) {
118 			return getRandomTrack(offset);
119 		} else {
120 			return getTrack(offset);
121 		}
122 	}
123 
124 	/**
125 	 * Get the Next Random Track
126 	 * 
127 	 * @param offset
128 	 * @return
129 	 */
130 	private CustomTrack getRandomTrack(int offset) {
131 		if (current_track != null) {
132 			if (!(current_track instanceof CustomChannel)) {
133 				try {
134 					int i = 0;
135 					for (String t : getShuffledTracks()) {
136 						if (t.equalsIgnoreCase("" + current_track.getId())) {
137 							break;
138 						}
139 						i++;
140 					}
141 					if (getShuffledTracks().size() > i + offset) {
142 						if (i + offset >= 0) {
143 							String track_id = getShuffledTracks().get(i + offset);
144 							CustomTrack newTrack = getTrackFromId(Integer.parseInt(track_id));
145 							log.debug("Returning Next Shuffled Track: " + newTrack.getUri());
146 							return (newTrack);
147 						}
148 					} else {
149 						log.info("We have Reached the End of the PlayList");
150 						if (isRepeatPlayList()) {
151 							log.info("Repeat Playlsit is Set so start again...");
152 							shuffleTracks();
153 							if (getShuffledTracks().size() > 0) {
154 								String track_id = getShuffledTracks().get(0);
155 								CustomTrack newTrack = getTrackFromId(Integer.parseInt(track_id));
156 								return newTrack;
157 							}
158 						} else {
159 							return null;
160 						}
161 					}
162 				} catch (Exception e) {
163 					log.error("Error GetNextTrack: ", e);
164 				}
165 			} else {
166 
167 			}
168 		}
169 		if (shuffled_tracks.size() > 0) {
170 			String id = shuffled_tracks.get(0);
171 			CustomTrack t = getTrackFromId(Integer.parseInt(id));
172 			return t;
173 		}
174 		return null;
175 	}
176 
177 	/***
178 	 * Get next or previous track
179 	 * 
180 	 * @param offset
181 	 * @return
182 	 */
183 	private CustomTrack getTrack(int offset) {
184 		if (current_track != null)
185 			try {
186 				log.debug("Getting Next Track, CurrentTrack is: " + current_track.getUri());
187 				int i = 0;
188 				for (CustomTrack t : getTracks()) {
189 					if (current_track.getId() == t.getId()) {
190 						break;
191 					}
192 					i++;
193 				}
194 				if (getTracks().size() > i + offset) {
195 					if (i + offset >= 0) {
196 						CustomTrack newTrack = getTracks().get(i + offset);
197 						log.debug("Returning Next Track: " + newTrack.getUri());
198 						return (newTrack);
199 					}
200 				} else {
201 					log.info("We have Reached the End of the PlayList");
202 					if (isRepeatPlayList()) {
203 						log.info("Repeat Playlsit is Set so start again...");
204 						if (getTracks().size() > 0) {
205 							CustomTrack newTrack = getTracks().get(0);
206 							return newTrack;
207 						}
208 					}
209 				}
210 			} catch (Exception e) {
211 				log.error("Error GetNextTrack: ", e);
212 			}
213 		else {
214 			if (tracks.size() > 0) {
215 				return tracks.get(0);
216 			}
217 		}
218 		return null;
219 	}
220 
221 	/***
222 	 * Get the Custom Track from the List
223 	 * 
224 	 * @param index
225 	 * @return
226 	 */
227 	public CustomTrack getTrackFromIndex(int index) {
228 		log.debug("GetTrackFromIndex: " + index);
229 		try {
230 			return tracks.get(index);
231 		} catch (Exception e) {
232 			log.error("Error gettingTrackFromId: ", e);
233 		}
234 		return null;
235 	}
236 
237 	/***
238 	 * Return a Custom Track from the given Track Id.
239 	 * 
240 	 * @param id
241 	 * @return
242 	 */
243 	public CustomTrack getTrackFromId(int id) {
244 		log.debug("GetTrakcFromId: " + id);
245 		for (CustomTrack t : tracks) {
246 			if (t.getId() == id) {
247 				return t;
248 			}
249 		}
250 		return null;
251 	}
252 
253 	public synchronized boolean isStandby() {
254 		return standby;
255 	}
256 
257 	public synchronized void setStandby(boolean standby) {
258 		this.standby = standby;
259 		EventStandbyChanged ev = new EventStandbyChanged();
260 		ev.setStandby(standby);
261 		obsvProduct.notifyChange(ev);
262 		if (standby)
263 			stop();
264 	}
265 
266 	/**
267 	 * 
268 	 * @return
269 	 */
270 	public boolean isRepeatPlayList() {
271 		return repeatPlayList;
272 	}
273 
274 	/**
275 	 * 
276 	 * @param repeatPlayList
277 	 */
278 	public void setRepeatPlayList(boolean repeatPlayList) {
279 		this.repeatPlayList = repeatPlayList;
280 	}
281 
282 	/**
283 	 * @return the shuffle
284 	 */
285 	public boolean isShuffle() {
286 		return shuffle;
287 	}
288 
289 	/**
290 	 * @param shuffle
291 	 *            the shuffle to set
292 	 */
293 	public void setShuffle(boolean shuffle) {
294 		if (shuffle)
295 			shuffleTracks();
296 		this.shuffle = shuffle;
297 	}
298 
299 	public void updateShuffle(boolean shuffle) {
300 		setShuffle(shuffle);
301 		EventPlayListUpdateShuffle ev = new EventPlayListUpdateShuffle();
302 		ev.setShuffle(shuffle);
303 		obsvPlayList.notifyChange(ev);
304 	}
305 
306 	/**
307 	 * Add the Next Shuffle Track Find the current track index in the shuffle
308 	 * list and insert after
309 	 * 
310 	 * @param t
311 	 */
312 	private void addAsNextShuffleTrack(CustomTrack t) {
313 		int this_track = getTrackIndexShuffled(t.getId());
314 		if (this_track >= 0) {
315 			shuffled_tracks.remove(this_track);
316 		}
317 		if (current_track != null) {
318 			if (!(current_track instanceof CustomChannel)) {
319 				int index = getTrackIndexShuffled(current_track.getId());
320 				if (index >= 0) {
321 					shuffled_tracks.add(index + 1, "" + t.getId());
322 					return;
323 				}
324 			}
325 		}
326 		shuffled_tracks.add(0, "" + t.getId());
327 
328 	}
329 
330 	/***
331 	 * Shuffle the tracks
332 	 */
333 	private void shuffleTracks() {
334 		shuffled_tracks.clear();
335 		for (CustomTrack t : tracks) {
336 			shuffled_tracks.add("" + t.getId());
337 		}
338 		long seed = System.nanoTime();
339 		Collections.shuffle(shuffled_tracks, new Random(seed));
340 		if (current_track != null) {
341 			if (current_track instanceof CustomChannel)
342 				return;
343 			log.debug("We have shuffled so set the current track to index ZERO");
344 			int index = getTrackIndexShuffled(current_track.getId());
345 			shuffled_tracks.remove(index);
346 			shuffled_tracks.add(0, "" + current_track.getId());
347 		}
348 	}
349 
350 	/**
351 	 * Generate a Random number in the range
352 	 * 
353 	 * @param min
354 	 * @param max
355 	 * @return
356 	 */
357 	private int generateRandonNumber(int min, int max) {
358 		long seed = System.nanoTime();
359 		Random rand = new Random(seed);
360 		int limit = (max - min) + min;
361 		if (limit == 0)
362 			limit = 1;
363 		int res = rand.nextInt(limit);
364 		log.debug("Random Number in range " + min + " - " + max + " = " + res);
365 		return res;
366 	}
367 
368 	/**
369 	 * @return the tracks
370 	 */
371 	private synchronized CopyOnWriteArrayList<CustomTrack> getTracks() {
372 		return tracks;
373 	}
374 
375 	/**
376 	 * @return the shuffled tracks
377 	 */
378 	private synchronized CopyOnWriteArrayList<String> getShuffledTracks() {
379 		return shuffled_tracks;
380 	}
381 
382 	/**
383 	 * Set the tracks from ProviderPlaylist Used at the start after reading
384 	 * playlist from the xml file.
385 	 * 
386 	 * @param tracks
387 	 */
388 	public synchronized void setTracks(CopyOnWriteArrayList<CustomTrack> tracks) {
389 		this.tracks = (CopyOnWriteArrayList<CustomTrack>) tracks.clone();
390 	}
391 
392 	public synchronized void setCurrentTrack(CustomTrack track) {
393 		current_track = track;
394 		log.debug("Current Track Id: " + track.getId());
395 	}
396 
397 	/**
398 	 * 
399 	 * @return
400 	 */
401 	public synchronized CustomTrack getCurrentTrack() {
402 		return current_track;
403 	}
404 
405 	/**
406 	 * 
407 	 */
408 	public synchronized void deletedAllTracks() {
409 		tracks.clear();
410 		shuffled_tracks.clear();
411 	}
412 
413 	public synchronized void deletedTrack(long iD) {
414 		int index = getTrackIndex(iD);
415 		if (index >= 0)
416 			tracks.remove(index);
417 		if (shuffled_tracks.contains("" + iD)) {
418 			shuffled_tracks.remove("" + iD);
419 		}
420 	}
421 
422 	/**
423 	 * Pause track
424 	 * 
425 	 * @param bPause
426 	 */
427 	public synchronized void pause(boolean bPause) {
428 		if (mPlayer.isPlaying()) {
429 			mPlayer.pause(bPause);
430 			setPaused(bPause);
431 			setStatus("Paused");
432 		}
433 	}
434 
435 	/**
436 	 * 
437 	 * @param paused
438 	 */
439 	private void setPaused(boolean paused) {
440 		bPaused = paused;
441 	}
442 
443 	/**
444 	 * 
445 	 * @return
446 	 */
447 	private boolean isPaused() {
448 		return bPaused;
449 	}
450 
451 	/**
452 	 * Stop playin Track
453 	 */
454 	public synchronized void stop() {
455 		if (mPlayer.isPlaying()) {
456 			mPlayer.stop();
457 		}
458 	}
459 
460 	/**
461 	 * Play track with Index Determine if shuffle is enabled, if we are not
462 	 * playing anything shuffle the tracks and set this track as the top track,
463 	 * else set this track as the top track and play
464 	 * 
465 	 * @param index
466 	 */
467 	public synchronized void playIndex(long index) {
468 		CustomTrack t = getTrackFromIndex((int) index);
469 		if (shuffle) {
470 			if (!mPlayer.isPlaying()) {
471 				shuffleTracks();
472 			}
473 			addAsNextShuffleTrack(t);
474 		}
475 		if (t != null) {
476 			playThis(t);
477 		} else {
478 			log.debug("Next Track was NULL");
479 		}
480 	}
481 	
482 	public synchronized void playTrackId(long id)
483 	{
484 		CustomTrack t = getTrackFromId((int)id);
485 		if(t !=null)
486 		{
487 			playThis(t);
488 		}
489 		else {
490 			log.debug("Next Track was NULL");
491 		}
492 	}
493 
494 	/**
495 	 * Play Track If Paused the resume If not Paused then get Next Track and
496 	 * play it
497 	 */
498 	public synchronized void play() {
499 		if (isPaused()) {
500 			if (mPlayer.isPlaying()) {
501 				mPlayer.resume();
502 			}
503 			setStatus("Playing");
504 			setPaused(false);
505 		} else {
506 			//if (!(status.equalsIgnoreCase("PLAYING") || status.equalsIgnoreCase("BUFFERING"))) {
507 				if(current_track ==null)
508 				{
509 					log.debug("CurrentTrack was NULL");
510 				}
511 				if (shuffle)
512 					shuffleTracks();
513 				CustomTrack t = getNextTrack(1);
514 				if (t != null) {
515 					playThis(t);
516 				}
517 			//}
518 			//else
519 			//{
520 			//	log.warn("Track is Already Playing, do not Play");
521 			//}
522 		}
523 	}
524 
525 	/**
526 	 * Play a Radio Channel
527 	 * 
528 	 * @param c
529 	 */
530 	public synchronized void playFile(CustomChannel c) {
531 		log.debug("Play Radio Id:  " + c.getId());
532 		playThis(c);
533 	}
534 	
535 	public synchronized void playAV(CustomTrack c)
536 	{
537 		log.debug("Play AV Track :  " + c.getUri());
538 		playThis(c);
539 	}
540 
541 	/**
542 	 * Used by Alarm Plugin to Start Playing a radio channel by name
543 	 * 
544 	 * @param name
545 	 */
546 	public synchronized void playRadio(String name) {
547 		EventRadioPlayName ev = new EventRadioPlayName();
548 		ev.setName(name);
549 		obsvRadio.notifyChange(ev);
550 	}
551 
552 	/***
553 	 * Play the Next Track
554 	 */
555 	public synchronized void nextTrack() {
556 		CustomTrack t = getNextTrack(1);
557 		if (t != null) {
558 			playThis(t);
559 		}
560 	}
561 
562 	/***
563 	 * Play the Previous Track
564 	 */
565 	public synchronized void previousTrack() {
566 		if (current_track != null) {
567 			if (current_track.getTime() > 0 && current_track.getTime() >= 5) {
568 				playThis(current_track);
569 				return;
570 			}
571 
572 		}
573 		CustomTrack t = getNextTrack(-1);
574 		if (t != null) {
575 			playThis(t);
576 		}
577 	}
578 
579 	/**
580 	 * Seek time in track, does not work for certain format types and VBR MP3's
581 	 * due to issue with MPLayer
582 	 * 
583 	 * @param seconds
584 	 */
585 	public synchronized void seekAbsolute(long seconds) {
586 		if (mPlayer.isPlaying()) {
587 			mPlayer.seekAbsolute(seconds);
588 		}
589 	}
590 
591 	// Volume Control
592 
593 	/**
594 	 * Set the Volume to this value
595 	 * 
596 	 * @param volume
597 	 */
598 	public synchronized void setVolume(long volume) {
599 		if (!bMute) {
600 			if(this.volume <0 ||volume > 100)
601 			{
602 				log.debug("Volume is less than Zero, assume the DAC doesn't support Hardware Volume Control");
603 				return;
604 			}
605 			this.volume = volume;
606 			log.debug("Set Volume");
607 			EventVolumeChanged ev = new EventVolumeChanged();
608 			ev.setVolume(volume);
609 			obsvVolume.notifyChange(ev);
610 			{
611 				if (mPlayer.isActive()) {
612 					if (!isUseExternalVolume())
613 						mPlayer.setVolume(volume);
614 				}
615 			}
616 		}
617 	}
618 
619 	/**
620 	 * Set Mute
621 	 * 
622 	 * @param mute
623 	 */
624 	public synchronized void setMute(boolean mute) {
625 		if(volume< 0)
626 		{
627 			log.debug("Volume is less than Zero, assume the DAC doesn't support Hardware Volume Control");
628 			return;
629 		}
630 		this.bMute = mute;
631 		EventMuteChanged em = new EventMuteChanged();
632 		em.setMute(mute);
633 		obsvProduct.notifyChange(em);
634 		obsvVolume.notifyChange(em);
635 
636 		// if (mPlayer != null) {
637 		if (mPlayer.isActive()) {
638 			if (!isUseExternalVolume())
639 				mPlayer.setMute(mute);
640 		}
641 		bMute = mute;
642 	}
643 
644 	/**
645 	 * Insert a track
646 	 * 
647 	 * @param aAfterId
648 	 * @param track
649 	 */
650 	public synchronized void insertTrack(long aAfterId, CustomTrack track) {
651 		insertAfterTrack(aAfterId, track);
652 		if (shuffle) {
653 			insertAfterShuffleTrack(aAfterId, track);
654 		}
655 	}
656 
657 	/**
658 	 * Insert into our main list of tracks
659 	 * 
660 	 * @param aAfterId
661 	 * @param track
662 	 */
663 	private void insertAfterTrack(long aAfterId, CustomTrack track) {
664 		int index = 0;
665 		if (aAfterId != 0)
666 			index = getTrackIndex(aAfterId) + 1;
667 		tracks.add(index, track);
668 	}
669 
670 	/**
671 	 * Insert into the shuffle list
672 	 * 
673 	 * @param aAfterId
674 	 * @param track
675 	 */
676 	private void insertAfterShuffleTrack(long aAfterId, CustomTrack track) {
677 		int index = 0;
678 		if (aAfterId != 0)
679 			index = getTrackIndexShuffled(aAfterId);
680 		if (current_track != null) {
681 			int current_index = getTrackIndexShuffled(current_track.getId());
682 			if (current_index == index) {
683 				shuffled_tracks.add(index + 1, "" + track.getId());
684 			} else {
685 				int random = generateRandonNumber(index, shuffled_tracks.size());
686 				shuffled_tracks.add(random, "" + track.getId());
687 			}
688 		} else {
689 			if (aAfterId != 0) {
690 				int random = generateRandonNumber(index, shuffled_tracks.size());
691 				shuffled_tracks.add(random, "" + track.getId());
692 			} else {
693 				shuffled_tracks.add(index, "" + track.getId());
694 			}
695 		}
696 	}
697 
698 	/***
699 	 * Find the index of the Track Number in the main List
700 	 * 
701 	 * @param aAfterId
702 	 * @return
703 	 */
704 	private int getTrackIndex(long aAfterId) {
705 		int i = 0;
706 		for (CustomTrack t : getTracks()) {
707 			if (aAfterId == t.getId()) {
708 				return i;
709 			}
710 			i++;
711 		}
712 		return -99;
713 	}
714 
715 	/***
716 	 * Find the index of the Track Number in the shuffled List
717 	 * 
718 	 * @param aAfterId
719 	 * @return
720 	 */
721 	private int getTrackIndexShuffled(long aAfterId) {
722 		int i = 0;
723 		for (String t : getShuffledTracks()) {
724 			if (t.equalsIgnoreCase("" + aAfterId)) {
725 				return i;
726 			}
727 			i++;
728 		}
729 		return -99;
730 	}
731 
732 	/***
733 	 * Delete All Tracks
734 	 */
735 	public synchronized void deleteAllTracks() {
736 		deletedAllTracks();
737 		if (!(getCurrentTrack() instanceof CustomChannel)) {
738 			current_track = null;
739 			if (mPlayer.isPlaying()) {
740 				mPlayer.stop();
741 			}
742 		}
743 
744 	}
745 
746 	/***
747 	 * Delete a Track, if it is playing stop the player
748 	 * 
749 	 * @param iD
750 	 */
751 	public synchronized void DeleteTrack(long iD) {
752 		deletedTrack(iD);
753 		CustomTrack t = getCurrentTrack();
754 		if (t != null)
755 			if (t.getId() == iD && !(t instanceof CustomChannel)) {
756 				if (mPlayer.isPlaying()) {
757 					mPlayer.stop();
758 				}
759 			}
760 	}
761 
762 	/***
763 	 * Destroy
764 	 */
765 	public synchronized void destroy() {
766 		log.debug("Start of destroy");
767 		if (mPlayer.isActive()) {
768 			log.debug("Attempt to Destroy MPlayer");
769 			mPlayer.destroy();
770 		}
771 	}
772 
773 	/***
774 	 * Set the Status of the Track
775 	 * 
776 	 * @param status
777 	 */
778 	public synchronized void setStatus(String status) {
779 		log.debug("SetStatus: " + status);
780 		this.status = status;
781 		EventTrackChanged ev = new EventTrackChanged();
782 		if (status.equalsIgnoreCase("PLAYING")) {
783 
784 			if (current_track != null) {
785 				playingTrack(current_track.getId());
786 				ev.setTrack(current_track);
787 				try {
788 					obsvInfo.notifyChange(ev);
789 				} catch (Exception e) {
790 					log.error("Error Notify: " + e);
791 				}
792 			}
793 
794 		}
795 		if (current_track instanceof CustomChannel) {
796 			EventRadioStatusChanged evr = new EventRadioStatusChanged();
797 			evr.setStatus(status);
798 			obsvRadio.notifyChange(evr);
799 		} else {
800 			EventPlayListStatusChanged evr = new EventPlayListStatusChanged();
801 			evr.setStatus(status);
802 			obsvPlayList.notifyChange(evr);
803 		}
804 	}
805 
806 	/***
807 	 * Update Control Point we are playing a track
808 	 * 
809 	 * @param iD
810 	 */
811 	public synchronized void playingTrack(int iD) {
812 		if (current_track instanceof CustomChannel) {
813 			EventRadioPlayingTrackID evrp = new EventRadioPlayingTrackID();
814 			evrp.setId(iD);
815 			obsvRadio.notifyChange(evrp);
816 		} else {
817 			EventPlayListPlayingTrackID evrp = new EventPlayListPlayingTrackID();
818 			evrp.setId(iD);
819 			obsvPlayList.notifyChange(evrp);
820 		}
821 	}
822 
823 	/***
824 	 * Increase the Volume
825 	 * 
826 	 * @return
827 	 */
828 	public synchronized long incVolume() {
829 		EventRequestVolumeInc ev = new EventRequestVolumeInc();
830 		obsvVolume.notifyChange(ev);
831 		if (volume < 100 ) {
832 			long v = volume;
833 			v++;
834 			setVolume(v);
835 		}
836 		return volume;
837 	}
838 
839 	/***
840 	 * Decrease the Volume
841 	 * 
842 	 * @return
843 	 */
844 	public synchronized long decVolume() {
845 		EventRequestVolumeDec ev = new EventRequestVolumeDec();
846 		obsvVolume.notifyChange(ev);
847 		if (volume > 0) {
848 			long v = volume;
849 			v--;
850 			setVolume(v);
851 		}
852 		return volume;
853 	}
854 
855 	/***
856 	 * Get the Volume
857 	 * 
858 	 * @return
859 	 */
860 	public synchronized long getVolume() {
861 		return volume;
862 	}
863 
864 	@Override
865 	public void update(Observable paramObservable, Object obj) {
866 		EventBase e = (EventBase) obj;
867 		switch (e.getType()) {
868 		case EVENTFINISHEDCURRENTTRACK:
869 			try {
870 				EventFinishedCurrentTrack evct = (EventFinishedCurrentTrack) e;
871 				if (evct.isQuit()) {
872 					log.debug("Track was Stopped, do not select Next Track");
873 				} else {
874 					log.debug("Track Stopped, get Next Track");
875 					CustomTrack t = getNextTrack(1);
876 					if (t != null) {
877 						playThis(t);
878 					}
879 				}
880 			} catch (Exception etf) {
881 				log.error("Error EVENTFINISHEDCURRENTTRACK", etf);
882 			}
883 			break;
884 		case EVENTCURRENTTRACKFINISHING:
885 			log.debug("Current Track is going to finish, get NextTrack and PreLoad");
886 			CustomTrack t = getNextTrack(1);
887 			if (t != null) {
888 				mPlayer.preLoadTrack(t);
889 			}
890 			break;
891 		case EVENTPLAYLISTPLAYINGTRACKID:
892 			obsvPlayList.notifyChange(e);
893 			break;
894 		case EVENTTIMEUPDATED:
895 			try {
896 				obsvTime.notifyChange(e);
897 				if (current_track != null) {
898 					EventTimeUpdate ed = (EventTimeUpdate) e;
899 					current_track.setTime(ed.getTime());
900 				}
901 			} catch (Exception etu) {
902 				log.error("Error EVENTTIMEUPDATED", etu);
903 			}
904 			break;
905 		case EVENTSTATUSCHANGED:
906 			try {
907 				EventStatusChanged es = (EventStatusChanged) e;
908 				log.debug("EventStatusChanged: " + es.getStatus());
909 				setStatus(es.getStatus());
910 				obsvAVTransport.notifyChange(es);
911 			} catch (Exception esc) {
912 				log.error("Error EVENTSTATUSCHANGED", esc);
913 			}
914 			break;
915 		case EVENTDURATIONUPDATE:
916 			try {
917 				obsvTime.notifyChange(e);
918 			} catch (Exception edu) {
919 				log.error("Error EVENTDURATIONUPDATE", edu);
920 			}
921 			break;
922 		case EVENTUPDATETRACKINFO:
923 			try {
924 				obsvInfo.notifyChange(e);
925 			} catch (Exception eut) {
926 				log.error("Error EVENTUPDATETRACKINFO", eut);
927 			}
928 			break;
929 		case EVENTUPDATETRACKMETATEXT:
930 			try {
931 				EventUpdateTrackMetaText etm = (EventUpdateTrackMetaText) e;
932 				if (current_track != null) {
933 					if (current_track instanceof CustomChannel) {
934 						if(current_track.isICYReverse())
935 						{
936 							String title = etm.getArtist();
937 							String artist = etm.getTitle();
938 							etm.setTitle(title);
939 							etm.setArtist(artist);
940 						}
941 						String metatext = current_track.updateTrack(etm.getTitle(), etm.getArtist());
942 						etm.setMetaText(metatext);
943 						obsvInfo.notifyChange(etm);
944 					}
945 				}
946 			} catch (Exception etm) {
947 				log.error("Error EVENTUPDATETRACKMETATEXT", etm);
948 			}
949 			break;
950 		case EVENTLOADED:
951 			try {
952 				log.debug("Track Loaded");
953 			} catch (Exception etl) {
954 				log.error("Error EVENTLOADED", etl);
955 			}
956 			break;
957 		case EVENTTRACKCHANGED:
958 			EventTrackChanged etc = (EventTrackChanged) e;
959 			current_track = etc.getTrack();
960 			break;
961 		case EVENTVOLUMECHANGED:
962 			try {
963 				EventVolumeChanged ev = (EventVolumeChanged) e;
964 				volume = ev.getVolume();
965 				obsvVolume.notifyChange(e);
966 			} catch (Exception ex) {
967 
968 			}
969 			break;
970 		// case EVENTMUTECHANGED:
971 		// try {
972 		// //EventMuteChanged emc = (EventMuteChanged) e;
973 		//
974 		// } catch (Exception exm) {
975 		//
976 		// }
977 		}
978 	}
979 
980 	/**
981 	 * Register for Time Events
982 	 * 
983 	 * @param o
984 	 */
985 	public synchronized void observTimeEvents(Observer o) {
986 		obsvTime.addObserver(o);
987 	}
988 
989 	/**
990 	 * Register for Info Events
991 	 * 
992 	 * @param o
993 	 */
994 	public synchronized void observInfoEvents(Observer o) {
995 		obsvInfo.addObserver(o);
996 	}
997 
998 	/**
999 	 * Register for Volume Events
1000 	 * 
1001 	 * @param o
1002 	 */
1003 	public synchronized void observVolumeEvents(Observer o) {
1004 		obsvVolume.addObserver(o);
1005 	}
1006 
1007 	/**
1008 	 * Register for PlayList Events
1009 	 * 
1010 	 * @param o
1011 	 */
1012 	public synchronized void observPlayListEvents(Observer o) {
1013 		obsvPlayList.addObserver(o);
1014 	}
1015 
1016 	/**
1017 	 * Register for Product Events
1018 	 * 
1019 	 * @param o
1020 	 */
1021 	public synchronized void observeProductEvents(Observer o) {
1022 		obsvProduct.addObserver(o);
1023 	}
1024 
1025 	/**
1026 	 * Register for Radio Events
1027 	 * 
1028 	 * @param o
1029 	 */
1030 	public synchronized void observRadioEvents(Observer o) {
1031 		obsvRadio.addObserver(o);
1032 	}
1033 	
1034 	public void observAVEvnts(Observer o) {
1035 		obsvAVTransport.addObserver(o);
1036 		
1037 	}
1038 
1039 	public synchronized boolean isUseExternalVolume() {
1040 		return bExternalVolume;
1041 	}
1042 
1043 	public synchronized void setUseExternalVolume(boolean bExternalVolume) {
1044 		this.bExternalVolume = bExternalVolume;
1045 	}
1046 
1047 	public synchronized void toggleMute() {
1048 		setMute(!bMute);
1049 	}
1050 
1051 	public synchronized boolean getMute() {
1052 		return bMute;
1053 	}
1054 
1055 	public void pause() {
1056 		pause(!bPaused);
1057 	}
1058 
1059 
1060 
1061 }