gt: 		if (audioThread != null) {
context: /*
   * Copyright 2008-2014, David Karnok 
   * The file is part of the Open Imperium Galactica project.
   * 
   * The code should be distributed under the LGPL license.
   * See http://www.gnu.org/licenses/lgpl.html for details.
   */
  
  package hu.openig.screen;
  
  import hu.openig.core.Action0;
  import hu.openig.core.Action1;
  import hu.openig.core.ResourceType;
  import hu.openig.core.SwappableRenderer;
  import hu.openig.model.ResourceLocator.ResourcePlace;
  import hu.openig.model.VideoAudio;
  import hu.openig.sound.AudioThread;
  import hu.openig.utils.Exceptions;
  
  import java.io.BufferedInputStream;
  import java.io.IOException;
  import java.util.concurrent.BrokenBarrierException;
  import java.util.concurrent.CyclicBarrier;
  import java.util.concurrent.atomic.AtomicInteger;
  
  import javax.sound.sampled.AudioFormat;
  import javax.sound.sampled.AudioInputStream;
  import javax.sound.sampled.AudioSystem;
  import javax.sound.sampled.DataLine;
  import javax.sound.sampled.LineUnavailableException;
  import javax.sound.sampled.SourceDataLine;
  import javax.sound.sampled.UnsupportedAudioFileException;
  import javax.swing.SwingUtilities;
  
  /**
   * A media player for playing video and audio.
   * @author akarnokd, 2010.01.17.
   */
  public class MediaPlayer {
  	/** The video thread. */
  	protected VideoRenderer videoThread;
  	/** The audio playback thread. */
  	protected Thread audioThread;
  	/** The audio playback channel. */
  	protected volatile SourceDataLine sdl;
  	/** The current subtitle manager. */
  	protected SubtitleManager subtitle;
  	/** Stop movie playback. */
  	protected volatile boolean stop;
  	/** Is the playback terminated. */
  	protected volatile boolean terminated;
  	/** The event to invoke when completed. */
  	public volatile Action0 onComplete;
  	/** The label event. */
  	public volatile Action1<String> onLabel;
  	/** The indicator to continue a phase. */
  	private AtomicInteger continuation;
  	/** The indicator to continue a phase. */
  	private AtomicInteger audioFinish;
  	/**
  	 * Constructor.
  	 * @param commons the commons resources
  	 * @param media the media to play
  	 * @param surface the rendering surface
  	 */
  	public MediaPlayer(final CommonResources commons, final String media, SwappableRenderer surface) {
  		init(commons, new VideoAudio(media, media), surface);
  	}
  	/**
  	 * Constructor.
  	 * @param commons the commons resources
  	 * @param media the media to play
  	 * @param surface the rendering surface
  	 */
  	public MediaPlayer(final CommonResources commons, final VideoAudio media, SwappableRenderer surface) {
  		init(commons, media, surface);
  	}
  	
  	/**
  	 * Initialize the playback threads.
  	 * @param commons the common resources
  	 * @param media the media record
  	 * @param surface the surface to render to
  	 */
  	private void init(final CommonResources commons, final VideoAudio media,
  			SwappableRenderer surface) {
  		final ResourcePlace audio = commons.audio(media.audio);
  		final ResourcePlace video = commons.video(media.video, true);
  		if (video == null) {
  			Exceptions.add(new AssertionError("Missing video: " + media.video));
  		}
  
  		final CyclicBarrier barrier = new CyclicBarrier(audio != null ? 2 : 1);
  		
  		continuation = new AtomicInteger(barrier.getParties());
  		audioFinish = new AtomicInteger(1);
  		
  		ResourcePlace sub = commons.rl.get(media.video, ResourceType.SUBTITLE);
  		if (sub != null) {
  			subtitle = new SubtitleManager(sub.open());
  		} else {
  			subtitle = null;
  		}
  		stop = false;
  //		final int audioSmooth = commons.config.videoFilter;
  		final int audioVolume = commons.config.muteVideo ? 0 : commons.config.videoVolume;
  		audioThread = new Thread(new Runnable() {
  			@Override
  			public void run() {
  				if (audio == null) {
  					return;
  				}
  				if (audioVolume <= 0) {
  					try {
  						barrier.await();
  					} catch (BrokenBarrierException ex) {
  						if (!stop) {
  							Exceptions.add(ex);
  						}
  					} catch (InterruptedException ex) {
  						// ignored, maybe cancel
  					}
  					doCompleteAudio();
  					return;
  				}
  				try (AudioInputStream in = AudioSystem.getAudioInputStream(new BufferedInputStream(
  							audio.open(), 256 * 1024))) {
  					byte[] buffer = new byte[in.available()];
  					in.read(buffer);
  					try {
  						AudioFormat af = in.getFormat();
  						byte[] buffer2;
  						if (af.getSampleSizeInBits() == 8) {
  							if (af.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED) {
  								for (int i = 0; i < buffer.length; i++) {
  									buffer[i] = (byte)((buffer[i] & 0xFF) - 128);
  								}
  							}
  							buffer2 = AudioThread.convert8To16(buffer);
  							af = new AudioFormat(af.getFrameRate(), 16, af.getChannels(), true, false);
  						} else {
  							buffer2 = buffer;
  						}
  						
  						DataLine.Info clipInfo = new DataLine.Info(SourceDataLine.class, af);
  						sdl = (SourceDataLine) AudioSystem.getLine(clipInfo);
  						sdl.open();
  						AudioThread.setVolume(sdl, audioVolume);
  						videoThread.setAudioLength(buffer2.length * 8 / af.getChannels() / af.getSampleSizeInBits());
  						try {
  							barrier.await();
  							if (!stop) {
  								sdl.start();
  								int chunkSize = 128 * 1024;
  								int bstart = 0;
  								while (!stop && bstart < buffer2.length) {
  									int blen = (bstart + chunkSize) > buffer2.length ? buffer2.length - bstart : chunkSize;
  									sdl.write(buffer2, bstart, blen);
  									bstart += blen;
  								}
  								sdl.drain();
  								sdl.stop();
  							}
  						} catch (InterruptedException ex) {
  							
  						} catch (BrokenBarrierException ex) {
  							if (!stop) {
  								Exceptions.add(ex);
  							}
  						} finally {
  							sdl.close();
  						}
  					} catch (LineUnavailableException ex) {
  						Exceptions.add(ex);
  					}
  				} catch (UnsupportedAudioFileException | IOException ex) {
  					Exceptions.add(ex);
  				} finally {
  					doCompleteAudio();
  				}
  			}
  		}, "Movie Audio");
  		
  		videoThread = new VideoRenderer(barrier, surface, video, "Movie Video",
  			new Action1<Void>() {
  				@Override
  				public void invoke(Void value) {
  					if (continuation.decrementAndGet() == 0) {
  						invokeComplete();
  					}
  				}
  			}
  		) {
  			@Override
  			public void onFrame(double fps, int frameIndex) {
  				setPosition(fps, frameIndex);
  			}
  		};
  	}
  	/** Invoke the completion action. */
  	void invokeComplete() {
  		SwingUtilities.invokeLater(new Runnable() {
  			@Override
  			public void run() {
  				if (onComplete != null && !terminated) {
  					onComplete.invoke();
  				}
  			}
  		});
  	}
  	/**
  	 * Upscale the 8 bit signed values to 16 bit signed values.
  	 * @param data the data to upscale
  	 * @return the upscaled data
  	 */
  	short[] upscale8To16AndSignify(byte[] data) {
  		short[] result = new short[data.length];
  		for (int i = 0; i < data.length; i++) {
  			result[i] = (short)(((data[i] & 0xFF) - 128) * 256);
  		}
  		return result;
  	}
  	/**
  	 * Set the label based on the current playback location.
  	 * @param fps the frames per second
  	 * @param frameCount the current frame count
  	 */
  	protected void setPosition(final double fps, final int frameCount) {
  		if (onLabel != null && subtitle != null) {
  			SwingUtilities.invokeLater(new Runnable() {
  				@Override
  				public void run() {
  					long time = (long)(frameCount * 1000 / fps);
  					onLabel.invoke(subtitle.get(time));
  				}
  			});
  		}
  	}
  	/**
  	 * Start the media playback.
  	 */
  	public void start() {
  