001: /*
002: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024: package com.sun.mmedia;
025:
026: import javax.microedition.media.*;
027: import javax.microedition.media.control.*;
028: import com.sun.mmedia.ABBBasicPlayer;
029: import java.io.*;
030:
031: public class QSoundABBToneSequencePlayer extends ABBBasicPlayer
032: implements Runnable {
033:
034: private QSoundABBMIDIPlayControl qsmc;
035:
036: private Object playLock = new Object();
037: private Thread playThread;
038: private boolean stopped;
039:
040: private QSoundABBToneCtrl tctrl;
041:
042: private final int bufferSize = 2048;
043:
044: public QSoundABBToneSequencePlayer() {
045: qsmc = new QSoundABBMIDIPlayControl(this );
046: tctrl = new QSoundABBToneCtrl(this );
047: }
048:
049: /**
050: * Subclasses need to implement this to realize
051: * the <code>Player</code>.
052: *
053: * @exception MediaException Description of the Exception
054: */
055: protected void doRealize() throws MediaException {
056: qsmc.open();
057:
058: stopped = true;
059:
060: if (source != null) {
061: int count;
062: byte[] b = new byte[bufferSize];
063:
064: // make use of BAOS, since it takes care of growing buffer
065: ByteArrayOutputStream baos = new ByteArrayOutputStream(
066: bufferSize);
067:
068: try {
069: while ((count = source.read(b, 0, bufferSize)) > 0)
070: baos.write(b, 0, count);
071:
072: boolean r = qsmc.fillBuffer(baos.toByteArray());
073:
074: baos.close();
075:
076: if (!r)
077: throw new MediaException("Bad Tone Format");
078: } catch (IOException ioe) {
079: throw new MediaException(
080: "Failure occured with read stream");
081: }
082:
083: baos = null;
084: }
085: }
086:
087: /**
088: * Subclasses need to implement this to prefetch
089: * the <code>Player</code>.
090: *
091: * @exception MediaException Description of the Exception
092: */
093: protected void doPrefetch() throws MediaException {
094:
095: }
096:
097: /**
098: * Subclasses need to implement this start
099: * the <code>Player</code>.
100: *
101: * @return Description of the Return Value
102: */
103: protected boolean doStart() {
104: /*
105: * TBD: wait until previous thread finishes before starting new one ...
106: * Does it make sense ? Or doStop() makes code below redundant ?
107: synchronized (playLock) {
108: if (playThread != null && playThread.isAlive()) {
109: //request thread to stop ex. stopped=true or doStop() ?
110: try { playThread.join(); } catch (InterruptedException ie) {};
111: }
112: }
113: */
114:
115: if (!stopped)
116: try {
117: doStop();
118: } catch (MediaException me) {
119: }
120: ; // Make sure the we were stopped.
121:
122: stopped = false;
123:
124: synchronized (playLock) {
125: playThread = new Thread(this );
126: playThread.start();
127: try {
128: playLock.wait();
129: } catch (InterruptedException ie) {
130: }
131: ;
132: }
133:
134: return true;
135: }
136:
137: /**
138: * Subclasses need to implement this to realize
139: * the <code>Player</code>.
140: *
141: * @exception MediaException Description of the Exception
142: */
143: protected void doStop() throws MediaException {
144: qsmc.stop();
145: stopped = true;
146: synchronized (playLock) {
147: try {
148: playThread.join();
149: } catch (InterruptedException ie) {
150: }
151: ;
152: }
153: }
154:
155: /**
156: * Subclasses need to implement this to deallocate
157: * the <code>Player</code>.
158: */
159: protected void doDeallocate() {
160:
161: }
162:
163: /**
164: * Subclasses need to implement this to close
165: * the <code>Player</code>.
166: */
167: protected void doClose() {
168: if (state != Player.UNREALIZED) {
169: if (!stopped)
170: try {
171: doStop();
172: } catch (MediaException me) {
173: }
174: ; // Make sure the we were stopped.
175:
176: qsmc.close();
177:
178: qsmc = null;
179: }
180: }
181:
182: /**
183: * Subclasses need to implement this to set the media time
184: * of the <code>Player</code>.
185: *
186: * @param now Description of the Parameter
187: * @return Description of the Return Value
188: * @exception MediaException Description of the Exception
189: */
190: protected long doSetMediaTime(long now) throws MediaException {
191: return qsmc.setMediaTime(now);
192: }
193:
194: /**
195: * Subclasses need to implement this to get the media time
196: * of the <code>Player</code>
197: *
198: * @return Description of the Return Value
199: */
200: protected long doGetMediaTime() {
201: return qsmc.getMediaTime();
202: }
203:
204: /**
205: * Subclasses need to implement this to get the duration
206: * of the <code>Player</code>.
207: *
208: * @return Description of the Return Value
209: */
210:
211: protected long doGetDuration() {
212: return qsmc.getDuration();
213: }
214:
215: /**
216: * The worker method to actually obtain the control.
217: *
218: * @param type the class name of the <code>Control</code>.
219: * @return <code>Control</code> for the class or interface
220: * name.
221: */
222: protected Control doGetControl(String controlType) {
223: Control r = null;
224:
225: if ((getState() != UNREALIZED)
226: && controlType.startsWith(ABBBasicPlayer.pkgName)) {
227:
228: controlType = controlType.substring(ABBBasicPlayer.pkgName
229: .length());
230:
231: if (controlType.equals(ABBBasicPlayer.tocName)) {
232: r = tctrl;
233: } else {
234: r = qsmc.getControl(controlType);
235: }
236: }
237:
238: return r;
239: }
240:
241: void doNextLoopIteration() {
242: }
243:
244: void doFinishLoopIteration() {
245: }
246:
247: protected void doSetLoopCount(int count) {
248: qsmc.setLoopCount(count);
249: }
250:
251: public void run() {
252: qsmc.start();
253:
254: synchronized (playLock) {
255: playLock.notify();
256: }
257:
258: boolean done = false;
259: int numLoopComplete = 0;
260:
261: while (!stopped) {
262: try {
263: Thread.sleep(500);
264: } catch (InterruptedException ie) {
265: }
266: ;
267:
268: done = qsmc.isDone();
269: numLoopComplete = qsmc.numLoopComplete();
270:
271: if (!done && (numLoopComplete > 0)) {
272: Long medt = new Long(qsmc.getMediaTime());
273: while (numLoopComplete-- > 0)
274: sendEvent(PlayerListener.END_OF_MEDIA, medt);
275:
276: }
277: if (done)
278: stopped = true;
279: }
280:
281: if (done) {
282: // updateTimeBase(false);
283: state = Player.PREFETCHED;
284: sendEvent(PlayerListener.END_OF_MEDIA, new Long(qsmc
285: .getMediaTime()));
286: }
287: }
288:
289: boolean setSequence(byte[] seq) throws IllegalArgumentException {
290: if (state == UNREALIZED)
291: qsmc.open();
292:
293: return qsmc.fillBuffer(seq);
294:
295: }
296:
297: public String getContentType() {
298: chkClosed(true);
299: return DefaultConfiguration.MIME_AUDIO_TONE;
300: }
301:
302: }
|