/******************************************************************************* * Copyright (c) 2009 Paul VanderLei, Simon Archer, Jeff McAffer and others. All * rights reserved. This program and the accompanying materials are made available * under the terms of the Eclipse Public License v1.0 and Eclipse Distribution License * v1.0 which accompanies this distribution. The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution License * is available at http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Paul VanderLei, Simon Archer, Jeff McAffer - initial API and implementation *******************************************************************************/ package org.eclipse.examples.toast.internal.dev.cdplayer.fake; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.examples.toast.dev.cdplayer.ICdPlayer; import org.eclipse.examples.toast.dev.cdplayer.ICdPlayerListener; public class FakeCdPlayer implements ICdPlayer { private static final int BIG_PRIME = 83; private static final int FAST_RATE = 7; // seconds of music private static final int FAKE_TRACK_COUNT = 8; private static final int[] FAKE_TRACK_TIMES = {253, 344, 381, 444, 199, 288, 202, 317}; private static final int NO_EVENT = 0; private static final int FAST_FORWARD_EVENT = 1; private static final int NEXT_TRACK_EVENT = 2; private static final int PAUSE_EVENT = 3; private static final int PLAY_EVENT = 4; private static final int PREVIOUS_TRACK_EVENT = 5; private static final int REWIND_EVENT = 6; private static final int STOP_EVENT = 7; private static final int EJECT_EVENT = 8; private static final int TICK_EVENT = 9; private List listeners; private boolean hasCd = true; private boolean isPlaying = false; private boolean isPaused = false; private boolean isFast = false; private boolean isForward = true; private boolean isRandomOn = false; private int track = 1; private int trackCount = FAKE_TRACK_COUNT; private int time = 0; private int[] trackTimes = FAKE_TRACK_TIMES; private Job job; private List eventQueue; public FakeCdPlayer() { super(); listeners = new ArrayList(2); eventQueue = new ArrayList(5); createJob(); } public void shutdown() { stopJob(); } // ICdPlayerService implementation public void addListener(ICdPlayerListener listener) { synchronized (listeners) { listeners.add(listener); } } public void removeListener(ICdPlayerListener listener) { synchronized (listeners) { listeners.remove(listener); } } public void eject() { addEvent(EJECT_EVENT); } public void fastForward() { addEvent(FAST_FORWARD_EVENT); } public int getTime() { return time; } public int getTrack() { return track; } public boolean hasCd() { return hasCd; } public boolean isPlaying() { return isPlaying; } public boolean isPausable() { return isPlaying && isPaused == false; } public boolean isPaused() { return isPaused; } public boolean isRandomOn() { return isRandomOn; } public void nextTrack() { addEvent(NEXT_TRACK_EVENT); } public void pause() { addEvent(PAUSE_EVENT); } public void play() { addEvent(PLAY_EVENT); } public void previousTrack() { addEvent(PREVIOUS_TRACK_EVENT); } public void rewind() { addEvent(REWIND_EVENT); } public void stop() { addEvent(STOP_EVENT); } public void turnRandomOff() { if (isRandomOn == true) { isRandomOn = false; notifyRandomChanged(); } } public void turnRandomOn() { if (isRandomOn == false) { isRandomOn = true; notifyRandomChanged(); } } // Private private void addEvent(int event) { synchronized (eventQueue) { eventQueue.add(new Integer(event)); } job.schedule(); } private void stopJob() { job.cancel(); try { job.join(); } catch (InterruptedException e) { // shutting down, ok to ignore } } private void createJob() { job = new Job("FakeCdPlayer") { protected IStatus run(IProgressMonitor monitor) { int event = getNextEvent(); processEvent(event); int reschedule = getTickDelay(); if (reschedule > 0) schedule(reschedule); return Status.OK_STATUS; } }; } private int getNextEvent() { synchronized (eventQueue) { if (eventQueue.isEmpty()) { return getTickDelay() > 0 ? TICK_EVENT : NO_EVENT; } Integer event = (Integer) eventQueue.remove(0); return event.intValue(); } } private int getTickDelay() { if (isPlaying && isPaused == false || isFast == true) { return isFast ? 500 : 1000; } return 0; } private void processEvent(int event) { switch (event) { case FAST_FORWARD_EVENT : fastForwardEvent(); break; case NEXT_TRACK_EVENT : nextTrackEvent(); break; case PAUSE_EVENT : pauseEvent(); break; case PLAY_EVENT : playEvent(); break; case PREVIOUS_TRACK_EVENT : previousTrackEvent(); break; case REWIND_EVENT : rewindEvent(); break; case STOP_EVENT : stopEvent(); break; case EJECT_EVENT : ejectEvent(); break; case TICK_EVENT : updateTime(); break; case NO_EVENT : default : break; } } // Notification private void notifyInserted() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.inserted(); } } } private void notifyEjected() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.ejected(); } } } private void notifyTrackChanged() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.trackChanged(track); } } } private void notifyTimeChanged() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.timeChanged(time); } } } private void notifyPaused() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.paused(); } } } private void notifyStarted() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.started(); } } } private void notifyStopped() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.stopped(); } } } private void notifyTrackCountChanged() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.trackCountChanged(trackCount); } } } private void notifyRandomChanged() { synchronized (listeners) { Iterator iterator = listeners.iterator(); while (iterator.hasNext()) { ICdPlayerListener listener = (ICdPlayerListener) iterator.next(); listener.randomChanged(isRandomOn); } } } // Event handlers private void updateTime() { int delta; if (isFast) { if (isForward) { delta = FAST_RATE; } else { delta = -FAST_RATE; } } else { delta = 1; } time += delta; if (time < 0) { if (track == 1) { // front of first track: stop stopEvent(); return; } track--; time = trackTimes[track - 1]; notifyTrackChanged(); } else if (time > trackTimes[track - 1]) { if (track == trackCount) { // end of last track: stop stopEvent(); return; } track++; time = 0; notifyTrackChanged(); } notifyTimeChanged(); } private void ejectEvent() { if (hasCd) { stopEvent(); hasCd = false; trackCount = 0; notifyTrackCountChanged(); track = 0; notifyTrackChanged(); notifyEjected(); } else { hasCd = true; notifyInserted(); trackCount = FAKE_TRACK_COUNT; notifyTrackCountChanged(); trackTimes = FAKE_TRACK_TIMES; track = 1; notifyTrackChanged(); notifyTimeChanged(); } } private void fastForwardEvent() { if (hasCd == false) { return; } if (isPlaying == false) { return; } if (isFast == false || isForward == false) { isFast = true; isForward = true; } } private void nextTrackEvent() { if (hasCd == false) { return; } isForward = true; isFast = false; int nextTrack = isRandomOn ? getRandomTrack() : track + 1; if (nextTrack > trackCount) { nextTrack = 1; } if (nextTrack <= trackCount) { track = nextTrack; notifyTrackChanged(); if (time != 0) { time = 0; notifyTimeChanged(); } } } private int getRandomTrack() { int randomTrack = track; for (int seed = BIG_PRIME; randomTrack == track; seed++) { int random = (int) (System.currentTimeMillis() % seed); randomTrack = random % trackCount + 1; } return randomTrack; } private void pauseEvent() { if (hasCd == false) { return; } if (isPlaying == false) { return; } if (isFast == true) { isFast = false; } if (isPaused == false) { isPaused = true; notifyPaused(); } } private void playEvent() { if (hasCd == false) { return; } if (isFast == true || isForward == false) { isFast = false; isForward = true; } if (isPaused || isPlaying == false) { isPaused = false; isPlaying = true; notifyStarted(); } } private void previousTrackEvent() { if (hasCd == false) { return; } isForward = true; isFast = false; if (time > 0) { time = 0; notifyTimeChanged(); } else { // start of a track int prevTrack = isRandomOn ? getRandomTrack() : track - 1; if (prevTrack == 0) { prevTrack = trackCount; } if (prevTrack >= 1) { track = prevTrack; notifyTrackChanged(); if (time != 0) { time = 0; notifyTimeChanged(); } } } } private void rewindEvent() { if (hasCd == false) { return; } if (isPlaying == false) { return; } if (isFast == false || isForward == true) { isFast = true; isForward = false; } } private void stopEvent() { if (hasCd == false) { return; } if (isPlaying == true) { isPlaying = false; isPaused = false; isFast = false; isForward = true; notifyStopped(); if (time != 0) { time = 0; notifyTimeChanged(); } } } }