988 } 989 } else { 990 break; 991 } 992 } 993 if (flushing) { 994 read = 0; 995 } 996 return read; 997 } 998 999 } 1000 1001 /** 1002 * Private inner class representing a Clip 1003 * This clip is realized in software only 1004 */ 1005 private static final class DirectClip extends DirectDL 1006 implements Clip, Runnable, AutoClosingClip { 1007 1008 private Thread thread; 1009 private byte[] audioData = null; 1010 private int frameSize; // size of one frame in bytes 1011 private int m_lengthInFrames; 1012 private int loopCount; 1013 private int clipBytePosition; // index in the audioData array at current playback 1014 private int newFramePosition; // set in setFramePosition() 1015 private int loopStartFrame; 1016 private int loopEndFrame; // the last sample included in the loop 1017 1018 // auto closing clip support 1019 private boolean autoclosing = false; 1020 1021 private DirectClip(DataLine.Info info, 1022 AudioFormat format, 1023 int bufferSize, 1024 DirectAudioDevice mixer) { 1025 super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), true); 1026 if (Printer.trace) Printer.trace("DirectClip CONSTRUCTOR: completed"); 1027 } 1028 1029 // CLIP METHODS 1030 1031 @Override 1032 public void open(AudioFormat format, byte[] data, int offset, int bufferSize) 1033 throws LineUnavailableException { 1034 1035 // $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions 1036 Toolkit.isFullySpecifiedAudioFormat(format); 1328 super.implStart(); 1329 if (Printer.trace) Printer.trace("< DirectClip: implStart() succeeded"); 1330 } 1331 1332 @Override 1333 void implStop() { 1334 if (Printer.trace) Printer.trace(">> DirectClip: implStop()"); 1335 1336 super.implStop(); 1337 // reset loopCount field so that playback will be normal with 1338 // next call to start() 1339 loopCount = 0; 1340 1341 if (Printer.trace) Printer.trace("<< DirectClip: implStop() succeeded"); 1342 } 1343 1344 // main playback loop 1345 @Override 1346 public void run() { 1347 if (Printer.trace) Printer.trace(">>> DirectClip: run() threadID="+Thread.currentThread().getId()); 1348 while (thread != null) { 1349 // doIO is volatile, but we could check it, then get 1350 // pre-empted while another thread changes doIO and notifies, 1351 // before we wait (so we sleep in wait forever). 1352 synchronized(lock) { 1353 if (!doIO) { 1354 try { 1355 lock.wait(); 1356 } catch(InterruptedException ie) {} 1357 } 1358 } 1359 while (doIO) { 1360 if (newFramePosition >= 0) { 1361 clipBytePosition = newFramePosition * frameSize; 1362 newFramePosition = -1; 1363 } 1364 int endFrame = getFrameLength() - 1; 1365 if (loopCount > 0 || loopCount == LOOP_CONTINUOUSLY) { 1366 endFrame = loopEndFrame; 1367 } 1368 long framePos = (clipBytePosition / frameSize); 1369 int toWriteFrames = (int) (endFrame - framePos + 1); 1370 int toWriteBytes = toWriteFrames * frameSize; 1371 if (toWriteBytes > getBufferSize()) { 1372 toWriteBytes = Toolkit.align(getBufferSize(), frameSize); 1373 } 1374 int written = write(audioData, clipBytePosition, toWriteBytes); // increases bytePosition 1375 clipBytePosition += written; 1376 // make sure nobody called setFramePosition, or stop() during the write() call | 988 } 989 } else { 990 break; 991 } 992 } 993 if (flushing) { 994 read = 0; 995 } 996 return read; 997 } 998 999 } 1000 1001 /** 1002 * Private inner class representing a Clip 1003 * This clip is realized in software only 1004 */ 1005 private static final class DirectClip extends DirectDL 1006 implements Clip, Runnable, AutoClosingClip { 1007 1008 private volatile Thread thread; 1009 private volatile byte[] audioData = null; 1010 private volatile int frameSize; // size of one frame in bytes 1011 private volatile int m_lengthInFrames; 1012 private volatile int loopCount; 1013 private volatile int clipBytePosition; // index in the audioData array at current playback 1014 private volatile int newFramePosition; // set in setFramePosition() 1015 private volatile int loopStartFrame; 1016 private volatile int loopEndFrame; // the last sample included in the loop 1017 1018 // auto closing clip support 1019 private boolean autoclosing = false; 1020 1021 private DirectClip(DataLine.Info info, 1022 AudioFormat format, 1023 int bufferSize, 1024 DirectAudioDevice mixer) { 1025 super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), true); 1026 if (Printer.trace) Printer.trace("DirectClip CONSTRUCTOR: completed"); 1027 } 1028 1029 // CLIP METHODS 1030 1031 @Override 1032 public void open(AudioFormat format, byte[] data, int offset, int bufferSize) 1033 throws LineUnavailableException { 1034 1035 // $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions 1036 Toolkit.isFullySpecifiedAudioFormat(format); 1328 super.implStart(); 1329 if (Printer.trace) Printer.trace("< DirectClip: implStart() succeeded"); 1330 } 1331 1332 @Override 1333 void implStop() { 1334 if (Printer.trace) Printer.trace(">> DirectClip: implStop()"); 1335 1336 super.implStop(); 1337 // reset loopCount field so that playback will be normal with 1338 // next call to start() 1339 loopCount = 0; 1340 1341 if (Printer.trace) Printer.trace("<< DirectClip: implStop() succeeded"); 1342 } 1343 1344 // main playback loop 1345 @Override 1346 public void run() { 1347 if (Printer.trace) Printer.trace(">>> DirectClip: run() threadID="+Thread.currentThread().getId()); 1348 Thread curThread = Thread.currentThread(); 1349 while (thread == curThread) { 1350 // doIO is volatile, but we could check it, then get 1351 // pre-empted while another thread changes doIO and notifies, 1352 // before we wait (so we sleep in wait forever). 1353 synchronized(lock) { 1354 if (!doIO) { 1355 try { 1356 lock.wait(); 1357 } catch(InterruptedException ie) { 1358 } finally { 1359 if (thread != curThread) { 1360 break; 1361 } 1362 } 1363 } 1364 } 1365 while (doIO) { 1366 if (newFramePosition >= 0) { 1367 clipBytePosition = newFramePosition * frameSize; 1368 newFramePosition = -1; 1369 } 1370 int endFrame = getFrameLength() - 1; 1371 if (loopCount > 0 || loopCount == LOOP_CONTINUOUSLY) { 1372 endFrame = loopEndFrame; 1373 } 1374 long framePos = (clipBytePosition / frameSize); 1375 int toWriteFrames = (int) (endFrame - framePos + 1); 1376 int toWriteBytes = toWriteFrames * frameSize; 1377 if (toWriteBytes > getBufferSize()) { 1378 toWriteBytes = Toolkit.align(getBufferSize(), frameSize); 1379 } 1380 int written = write(audioData, clipBytePosition, toWriteBytes); // increases bytePosition 1381 clipBytePosition += written; 1382 // make sure nobody called setFramePosition, or stop() during the write() call |