public void run() {
		byte[] data = soundClip.getData();
		int nChannels = soundClip.getChannelCount();
		int offset = soundClip.getFrameIndex() * nChannels * BYTES_PER_SAMPLE;
		int length = soundClip.getFrameCount() * nChannels * BYTES_PER_SAMPLE;
		SourceDataLine line = openSourceDataLine(Math.min(MAX_BUFFER_SIZE, length));
		line.start();
		while (thread != null) {
			int bytesRemaining = length - offset;
			while (thread != null && bytesRemaining > 0) {
				setLineVolume(line, soundClip.getVolume());
				int chunkSize = Math.min(MAX_BUFFER_SIZE, bytesRemaining);
				int nBytes = line.write(data, offset, chunkSize);
				offset += nBytes;
				bytesRemaining -= nBytes;
			}
			if (!looping) break;
			offset = 0;
		}
		if (thread == null) {
			soundClip.setFrameIndex(offset / nChannels / BYTES_PER_SAMPLE);
		}
		data = new byte[PADDING];
		line.write(data, 0, data.length);
		line.drain();
		line.stop();
		line.close();
		thread = null;
	}