@Override
	public void run() {
		this.mJoinLock.lock();
		try {
			MusicPlayerException exception = null;
			boolean failure = false;
			try {
				if ( this.mAlreadyStarted ) {
					throw new IllegalStateException( "has alredy been started once!" );
				}
				this.mAlreadyStarted = true;
				int bytesRead = 0;
				Audio audio = this.mAudio;
				AudioDevice dev = this.mAudioDevice;
				AudioFormat format = audio.getAudioFormat();
				if ( format != null ) {
					int bufferSize = (int) format.getSampleRate() *
							format.getFrameSize();
					byte[] data = new byte[bufferSize];
					while ( bytesRead != -1 ) {
						this.mPause.probe();
						if ( !this.mStopped ) {
							bytesRead = audio.read( data, 0, bufferSize );
							if ( bytesRead != -1 ) {
								dev.write( data, 0, bytesRead );
							}
						}
						else {
							break;
						}
					}
				}
				else {
					throw new IllegalStateException( "The AudioFormat was null" );
				}
			}
			catch (Exception e) {
				//catch all the exceptions so the user can handle them even if he can do that only via the listener
				failure = true;
				exception = new MusicPlayerException(
						"An Exception occured during Playback",
						e
				);
				this.mPlayerRunnableListener
						.onException(
								new MusicExceptionEvent(
										this.mMusicPlayer,
										exception
								)
						);
			}
			finally {
				MusicEndEvent.Type type = failure ? MusicEndEvent.Type.FAILURE
						: MusicEndEvent.Type.SUCCESS;
				if ( this.mStopped ) {
					type = MusicEndEvent.Type.MANUALLY_STOPPED;
				}
				this.mStopped = true;
				final MusicEndEvent.Type finalType = type;
				StreamPlayerRunnable.this.mPlayerRunnableListener
						.onEnd(
								new MusicEndEvent(
										StreamPlayerRunnable.this.mMusicPlayer,
										finalType
								)
						);
				this.mJoinCondition.signal();
				this.mDone = true;
			}
		}
		finally {
			this.mJoinLock.unlock();
		}
	}