diff options
Diffstat (limited to 'src/jogl/classes/jogamp')
-rw-r--r-- | src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java | 240 |
1 files changed, 125 insertions, 115 deletions
diff --git a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java index ecb6b60e8..1229eb7b8 100644 --- a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java +++ b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java @@ -3,14 +3,14 @@ * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. @@ -53,22 +53,22 @@ public class ALAudioSink implements AudioSink { private static final ALC alc; private static final AL al; private static final ALExt alExt; - private static final boolean staticAvailable; - + private static final boolean staticAvailable; + private String deviceSpecifier; private ALCdevice device; private boolean hasSOFTBufferSamples; - private AudioFormat preferredAudioFormat; + private AudioFormat preferredAudioFormat; private ALCcontext context; private final RecursiveLock lock = LockFactory.createRecursiveLock(); /** Playback speed, range [0.5 - 2.0], default 1.0. */ private float playSpeed; private float volume = 1.0f; - + static class ALAudioFrame extends AudioFrame { private final int alBuffer; - + ALAudioFrame(int alBuffer) { this.alBuffer = alBuffer; } @@ -76,20 +76,20 @@ public class ALAudioSink implements AudioSink { super(pts, duration, dataSize); this.alBuffer = alBuffer; } - + /** Get this frame's OpenAL buffer name */ public final int getALBuffer() { return alBuffer; } - - public String toString() { + + public String toString() { return "ALAudioFrame[pts " + pts + " ms, l " + duration + " ms, " + byteSize + " bytes, buffer "+alBuffer+"]"; } } - + // private ALAudioFrame[] alFrames = null; private int[] alBufferNames = null; private int frameGrowAmount = 0; private int frameLimit = 0; - + private Ringbuffer<ALAudioFrame> alFramesAvail = null; private Ringbuffer<ALAudioFrame> alFramesPlaying = null; private volatile int alBufferBytesQueued = 0; @@ -102,7 +102,7 @@ public class ALAudioSink implements AudioSink { private int alSampleType; private int alFormat; private boolean initialized; - + private volatile boolean playRequested = false; static { @@ -110,7 +110,7 @@ public class ALAudioSink implements AudioSink { AL _al = null; ALExt _alExt = null; try { - _alc = ALFactory.getALC(); + _alc = ALFactory.getALC(); _al = ALFactory.getAL(); _alExt = ALFactory.getALExt(); } catch(Throwable t) { @@ -124,41 +124,41 @@ public class ALAudioSink implements AudioSink { alExt = _alExt; staticAvailable = null != alc && null != al && null != alExt; } - + public ALAudioSink() { initialized = false; chosenFormat = null; - + if( !staticAvailable ) { return; } - + try { // Get handle to default device. device = alc.alcOpenDevice(null); if (device == null) { throw new RuntimeException("ALAudioSink: Error opening default OpenAL device"); } - + // Get the device specifier. deviceSpecifier = alc.alcGetString(device, ALC.ALC_DEVICE_SPECIFIER); if (deviceSpecifier == null) { throw new RuntimeException("ALAudioSink: Error getting specifier for default OpenAL device"); } - + // Create audio context. context = alc.alcCreateContext(device, null); if (context == null) { throw new RuntimeException("ALAudioSink: Error creating OpenAL context for "+deviceSpecifier); } - + lockContext(); try { // Check for an error. if ( alc.alcGetError(device) != ALC.ALC_NO_ERROR ) { throw new RuntimeException("ALAudioSink: Error making OpenAL context current"); } - + hasSOFTBufferSamples = al.alIsExtensionPresent(AL_SOFT_buffer_samples); preferredAudioFormat = queryPreferredAudioFormat(); if( DEBUG ) { @@ -168,7 +168,7 @@ public class ALAudioSink implements AudioSink { System.out.println("ALAudioSink: hasSOFTBufferSamples "+hasSOFTBufferSamples); System.out.println("ALAudioSink: preferredAudioFormat "+preferredAudioFormat); } - + // Create source { alSource = new int[1]; @@ -177,10 +177,10 @@ public class ALAudioSink implements AudioSink { if( err != AL.AL_NO_ERROR ) { alSource = null; throw new RuntimeException("ALAudioSink: Error generating Source: 0x"+Integer.toHexString(err)); - } + } } - - if( DEBUG ) { + + if( DEBUG ) { System.err.println("ALAudioSink: Using device: " + deviceSpecifier); } initialized = true; @@ -195,7 +195,7 @@ public class ALAudioSink implements AudioSink { destroy(); } } - + private final AudioFormat queryPreferredAudioFormat() { int sampleRate = DefaultFormat.sampleRate; final int[] value = new int[1]; @@ -205,7 +205,7 @@ public class ALAudioSink implements AudioSink { } return new AudioFormat(sampleRate, DefaultFormat.sampleSize, DefaultFormat.channelCount, DefaultFormat.signed, DefaultFormat.fixedP, DefaultFormat.planar, DefaultFormat.littleEndian); } - + private final void lockContext() { lock.lock(); alc.alcMakeContextCurrent(context); @@ -236,12 +236,12 @@ public class ALAudioSink implements AudioSink { lock.unlock(); } } - + @Override public final String toString() { final int alSrcName = null != alSource ? alSource[0] : 0; final int alBuffersLen = null != alBufferNames ? alBufferNames.length : 0; - final int ctxHash = context != null ? context.hashCode() : 0; + final int ctxHash = context != null ? context.hashCode() : 0; return "ALAudioSink[init "+initialized+", playRequested "+playRequested+", device "+deviceSpecifier+", ctx "+toHexString(ctxHash)+", alSource "+alSrcName+ ", chosen "+chosenFormat+ ", al[chan "+ALHelpers.alChannelLayoutName(alChannelLayout)+", type "+ALHelpers.alSampleTypeName(alSampleType)+ @@ -250,12 +250,12 @@ public class ALAudioSink implements AudioSink { "queued["+alFramesPlaying.size()+", apts "+getPTS()+", "+getQueuedTime() + " ms, " + alBufferBytesQueued+" bytes], "+ "queue[g "+frameGrowAmount+", l "+frameLimit+"]"; } - + public final String getPerfString() { final int alBuffersLen = null != alBufferNames ? alBufferNames.length : 0; return "Play [buffer "+alFramesPlaying.size()+"/"+alBuffersLen+", apts "+getPTS()+", "+getQueuedTime() + " ms, " + alBufferBytesQueued+" bytes]"; } - + @Override public final AudioFormat getPreferredFormat() { if( !staticAvailable ) { @@ -263,7 +263,7 @@ public class ALAudioSink implements AudioSink { } return preferredAudioFormat; } - + @Override public final int getMaxSupportedChannels() { if( !staticAvailable ) { @@ -271,14 +271,14 @@ public class ALAudioSink implements AudioSink { } return hasSOFTBufferSamples ? 8 : 2; } - + @Override public final boolean isSupported(AudioFormat format) { if( !staticAvailable ) { return false; } if( format.planar || !format.littleEndian ) { - // FIXME big-endian supported w/ SOFT where it's native format! + // FIXME big-endian supported w/ SOFT where it's native format! return false; } final int alChannelLayout = ALHelpers.getDefaultALChannelLayout(format.channelCount); @@ -286,7 +286,7 @@ public class ALAudioSink implements AudioSink { final int alSampleType = ALHelpers.getALSampleType(format.sampleSize, format.signed, format.fixedP); if( AL.AL_NONE != alSampleType ) { lockContext(); - try { + try { final int alFormat = ALHelpers.getALFormat(alChannelLayout, alSampleType, hasSOFTBufferSamples, al, alExt); return AL.AL_NONE != alFormat; } finally { @@ -296,7 +296,7 @@ public class ALAudioSink implements AudioSink { } return false; } - + @Override public final boolean init(AudioFormat requestedFormat, float frameDuration, int initialQueueSize, int queueGrowAmount, int queueLimit) { if( !staticAvailable ) { @@ -318,10 +318,10 @@ public class ALAudioSink implements AudioSink { // Allocate buffers destroyBuffers(); { - final float useFrameDuration = frameDuration > 1f ? frameDuration : AudioSink.DefaultFrameDuration; + final float useFrameDuration = frameDuration > 1f ? frameDuration : AudioSink.DefaultFrameDuration; final int initialFrameCount = requestedFormat.getFrameCount( initialQueueSize > 0 ? initialQueueSize : AudioSink.DefaultInitialQueueSize, useFrameDuration); - // frameDuration, int initialQueueSize, int queueGrowAmount, int queueLimit) { + // frameDuration, int initialQueueSize, int queueGrowAmount, int queueLimit) { alBufferNames = new int[initialFrameCount]; al.alGenBuffers(initialFrameCount, alBufferNames, 0); final int err = al.alGetError(); @@ -333,7 +333,7 @@ public class ALAudioSink implements AudioSink { for(int i=0; i<initialFrameCount; i++) { alFrames[i] = new ALAudioFrame(alBufferNames[i]); } - + alFramesAvail = new LFRingbuffer<ALAudioFrame>(alFrames); alFramesPlaying = new LFRingbuffer<ALAudioFrame>(ALAudioFrame[].class, initialFrameCount); this.frameGrowAmount = requestedFormat.getFrameCount( @@ -344,11 +344,11 @@ public class ALAudioSink implements AudioSink { } finally { unlockContext(); } - + chosenFormat = requestedFormat; return true; } - + private static int[] concat(int[] first, int[] second) { final int[] result = Arrays.copyOf(first, first.length + second.length); System.arraycopy(second, 0, result, first.length, second.length); @@ -360,7 +360,7 @@ public class ALAudioSink implements AudioSink { System.arraycopy(second, 0, result, first.length, second.length); return result; } */ - + private boolean growBuffers() { if( !alFramesAvail.isEmpty() || !alFramesPlaying.isFull() ) { throw new InternalError("Buffers: Avail is !empty "+alFramesAvail+" or Playing is !full "+alFramesPlaying); @@ -371,7 +371,7 @@ public class ALAudioSink implements AudioSink { } return false; } - + final int[] newALBufferNames = new int[frameGrowAmount]; al.alGenBuffers(frameGrowAmount, newALBufferNames, 0); final int err = al.alGetError(); @@ -382,7 +382,7 @@ public class ALAudioSink implements AudioSink { return false; } alBufferNames = concat(alBufferNames, newALBufferNames); - + final ALAudioFrame[] newALBuffers = new ALAudioFrame[frameGrowAmount]; for(int i=0; i<frameGrowAmount; i++) { newALBuffers[i] = new ALAudioFrame(newALBufferNames[i]); @@ -399,7 +399,7 @@ public class ALAudioSink implements AudioSink { } return true; } - + private void destroyBuffers() { if( !staticAvailable ) { return; @@ -422,7 +422,7 @@ public class ALAudioSink implements AudioSink { alBufferNames = null; } } - + @Override public final void destroy() { initialized = false; @@ -445,7 +445,7 @@ public class ALAudioSink implements AudioSink { } alSource = null; } - + destroyBuffers(); } finally { destroyContext(); @@ -459,22 +459,20 @@ public class ALAudioSink implements AudioSink { t.printStackTrace(); } } - device = null; + device = null; } chosenFormat = null; } - + @Override public final boolean isInitialized() { return initialized; } - - private final int dequeueBuffer(boolean flush, boolean wait) { + + private final int dequeueBuffer(boolean wait) { int alErr = AL.AL_NO_ERROR; final int releaseBufferCount; - if( flush ) { - releaseBufferCount = alFramesPlaying.size(); - } else if( alBufferBytesQueued > 0 ) { + if( alBufferBytesQueued > 0 ) { final int releaseBufferLimes = Math.max(1, alFramesPlaying.size() / 4 ); final int[] val=new int[1]; int i=0; @@ -490,8 +488,8 @@ public class ALAudioSink implements AudioSink { final int avgBufferDura = chosenFormat.getBytesDuration( alBufferBytesQueued / alFramesPlaying.size() ); final int sleep = Math.max(2, Math.min(100, releaseBufferLimes * avgBufferDura)); if( DEBUG || true ) { - System.err.println(getThreadName()+": ALAudioSink: Dequeue.wait["+i+"]: avgBufferDura "+avgBufferDura+", releaseBufferLimes "+releaseBufferLimes+", sleep "+sleep+" ms, playImpl "+isPlayingImpl1()+", processed "+val[0]+", "+this); - } + System.err.println(getThreadName()+": ALAudioSink: Dequeue.wait["+i+"]: avgBufferDura "+avgBufferDura+", releaseBufferLimes "+releaseBufferLimes+", sleep "+sleep+" ms, playImpl "+(AL.AL_PLAYING == getSourceState())+", processed "+val[0]+", "+this); + } unlockContext(); try { Thread.sleep( sleep - 1 ); @@ -511,7 +509,7 @@ public class ALAudioSink implements AudioSink { al.alSourceUnqueueBuffers(alSource[0], releaseBufferCount, buffers, 0); alErr = al.alGetError(); if( AL.AL_NO_ERROR != alErr ) { - throw new RuntimeException("ALError "+toHexString(alErr)+" while dequeueing "+releaseBufferCount+" buffers. "+this); + throw new RuntimeException("ALError "+toHexString(alErr)+" while dequeueing "+releaseBufferCount+" buffers. "+this); } for ( int i=0; i<releaseBufferCount; i++ ) { final ALAudioFrame releasedBuffer = alFramesPlaying.get(); @@ -520,7 +518,7 @@ public class ALAudioSink implements AudioSink { } if( releasedBuffer.alBuffer != buffers[i] ) { alFramesAvail.dump(System.err, "Avail-deq02-post"); - alFramesPlaying.dump(System.err, "Playi-deq02-post"); + alFramesPlaying.dump(System.err, "Playi-deq02-post"); throw new InternalError("Buffer name mismatch: dequeued: "+buffers[i]+", released "+releasedBuffer+", "+this); } alBufferBytesQueued -= releasedBuffer.getByteSize(); @@ -528,17 +526,27 @@ public class ALAudioSink implements AudioSink { throw new InternalError("Internal Error: "+this); } } - if( flush && ( !alFramesAvail.isFull() || !alFramesPlaying.isEmpty() ) ) { - alFramesAvail.dump(System.err, "Avail-deq03-post"); - alFramesPlaying.dump(System.err, "Playi-deq03-post"); - throw new InternalError("Flush failure: "+this); - } } return releaseBufferCount; } - + private final void dequeueForceAll() { + while ( !alFramesPlaying.isEmpty() ) { + final ALAudioFrame releasedBuffer = alFramesPlaying.get(); + if( null == releasedBuffer ) { + throw new InternalError("Internal Error: "+this); + } + alBufferBytesQueued -= releasedBuffer.getByteSize(); + if( !alFramesAvail.put(releasedBuffer) ) { + throw new InternalError("Internal Error: "+this); + } + } + if( 0 != alBufferBytesQueued ) { + throw new InternalError("Internal Error: "+this); + } + } + private final int dequeueBuffer(boolean wait, int inPTS, int inDuration) { - final int dequeuedBufferCount = dequeueBuffer( false /* flush */, wait ); + final int dequeuedBufferCount = dequeueBuffer( wait ); final ALAudioFrame currentBuffer = alFramesPlaying.peek(); if( null != currentBuffer ) { playingPTS = currentBuffer.getPTS(); @@ -552,12 +560,12 @@ public class ALAudioSink implements AudioSink { } return dequeuedBufferCount; } - + @Override public final AudioFrame enqueueData(AudioDataFrame audioDataFrame) { return enqueueData(audioDataFrame.getPTS(), audioDataFrame.getData(), audioDataFrame.getByteSize()); } - + @Override public final AudioFrame enqueueData(int pts, ByteBuffer bytes, int byteCount) { if( !initialized || null == chosenFormat ) { @@ -565,7 +573,7 @@ public class ALAudioSink implements AudioSink { } final ALAudioFrame alFrame; int alErr = AL.AL_NO_ERROR; - + // OpenAL consumes buffers in the background // we first need to initialize the OpenAL buffers then // start continuous playback. @@ -575,7 +583,7 @@ public class ALAudioSink implements AudioSink { if(al.alGetError() != AL.AL_NO_ERROR) { throw new RuntimeException("ALError "+toHexString(alErr)+" while makeCurrent. "+this); } - + final int duration = chosenFormat.getBytesDuration(byteCount); final boolean dequeueDone; if( alFramesAvail.isEmpty() ) { @@ -592,7 +600,7 @@ public class ALAudioSink implements AudioSink { final boolean wait = isPlayingImpl0() && alFramesAvail.isEmpty(); // possible if grow failed or already exceeds it's limit! dequeueBuffer(wait, pts, duration); } - + alFrame = alFramesAvail.get(); if( null == alFrame ) { alFramesAvail.dump(System.err, "Avail"); @@ -612,7 +620,7 @@ public class ALAudioSink implements AudioSink { } else { al.alBufferData(alFrame.alBuffer, alFormat, bytes, byteCount, chosenFormat.sampleRate); } - + final int[] alBufferNames = new int[] { alFrame.alBuffer }; al.alSourceQueueBuffers(alSource[0], 1, alBufferNames, 0); alErr = al.alGetError(); @@ -621,7 +629,7 @@ public class ALAudioSink implements AudioSink { } alBufferBytesQueued += byteCount; enqueuedFrameCount++; - + playImpl(); // continue playing, fixes issue where we ran out of enqueued data! } finally { unlockContext(); @@ -640,28 +648,28 @@ public class ALAudioSink implements AudioSink { return isPlayingImpl0(); } finally { unlockContext(); - } + } } else { return false; } } private final boolean isPlayingImpl0() { if( playRequested ) { - return isPlayingImpl1(); + return AL.AL_PLAYING == getSourceState(); } else { return false; } } - private final boolean isPlayingImpl1() { + private final int getSourceState() { final int[] val = new int[1]; al.alGetSourcei(alSource[0], AL.AL_SOURCE_STATE, val, 0); final int alErr = al.alGetError(); if(al.alGetError() != AL.AL_NO_ERROR) { - throw new RuntimeException("ALError "+toHexString(alErr)+" while querying isPlaying. "+this); + throw new RuntimeException("ALError "+toHexString(alErr)+" while querying SOURCE_STATE. "+this); } - return val[0] == AL.AL_PLAYING; + return val[0]; } - + @Override public final void play() { if( !initialized || null == chosenFormat ) { @@ -672,22 +680,22 @@ public class ALAudioSink implements AudioSink { try { playImpl(); if( DEBUG ) { - System.err.println(getThreadName()+": ALAudioSink: PLAY playImpl "+isPlayingImpl1()+", "+this); - } + System.err.println(getThreadName()+": ALAudioSink: PLAY playImpl "+(AL.AL_PLAYING == getSourceState())+", "+this); + } } finally { unlockContext(); - } + } } private final void playImpl() { - if( playRequested && !isPlayingImpl1() ) { + if( playRequested && AL.AL_PLAYING != getSourceState() ) { al.alSourcePlay(alSource[0]); final int alErr = al.alGetError(); if(al.alGetError() != AL.AL_NO_ERROR) { throw new RuntimeException("ALError "+toHexString(alErr)+" while start playing. "+this); } - } + } } - + @Override public final void pause() { if( !initialized || null == chosenFormat ) { @@ -698,8 +706,8 @@ public class ALAudioSink implements AudioSink { try { pauseImpl(); if( DEBUG ) { - System.err.println(getThreadName()+": ALAudioSink: PAUSE playImpl "+isPlayingImpl1()+", "+this); - } + System.err.println(getThreadName()+": ALAudioSink: PAUSE playImpl "+(AL.AL_PLAYING == getSourceState())+", "+this); + } } finally { unlockContext(); } @@ -716,7 +724,7 @@ public class ALAudioSink implements AudioSink { } } private final void stopImpl() { - if( isPlayingImpl0() ) { + if( AL.AL_STOPPED != getSourceState() ) { playRequested = false; al.alSourceStop(alSource[0]); final int alErr = al.alGetError(); @@ -725,12 +733,12 @@ public class ALAudioSink implements AudioSink { } } } - + @Override public final float getPlaySpeed() { return playSpeed; } - + @Override - public final boolean setPlaySpeed(float rate) { + public final boolean setPlaySpeed(float rate) { if( !initialized || null == chosenFormat ) { return false; } @@ -739,22 +747,22 @@ public class ALAudioSink implements AudioSink { if( Math.abs(1.0f - rate) < 0.01f ) { rate = 1.0f; } - if( 0.5f <= rate && rate <= 2.0f ) { // OpenAL limits + if( 0.5f <= rate && rate <= 2.0f ) { // OpenAL limits playSpeed = rate; al.alSourcef(alSource[0], AL.AL_PITCH, playSpeed); return true; - } + } } finally { unlockContext(); } - return false; + return false; } - + @Override public final float getVolume() { - return volume; + return volume; } - + @Override public final boolean setVolume(float v) { if( !initialized || null == chosenFormat ) { @@ -767,17 +775,17 @@ public class ALAudioSink implements AudioSink { } else if( Math.abs(1.0f - v) < 0.01f ) { v = 1.0f; } - if( 0.0f <= v && v <= 1.0f ) { // OpenAL limits + if( 0.0f <= v && v <= 1.0f ) { // OpenAL limits volume = v; al.alSourcef(alSource[0], AL.AL_GAIN, v); return true; - } + } } finally { unlockContext(); } - return false; + return false; } - + @Override public final void flush() { if( !initialized || null == chosenFormat ) { @@ -787,28 +795,30 @@ public class ALAudioSink implements AudioSink { try { // pauseImpl(); stopImpl(); - dequeueBuffer( true /* flush */, false /* wait */ ); + al.alSourcei(alSource[0], AL.AL_BUFFER, 0); // explicit force zero buffer! + dequeueBuffer( false /* wait */ ); + dequeueForceAll(); if( alBufferNames.length != alFramesAvail.size() || alFramesPlaying.size() != 0 ) { throw new InternalError("XXX: "+this); } if( DEBUG ) { - System.err.println(getThreadName()+": ALAudioSink: FLUSH playImpl "+isPlayingImpl1()+", "+this); - } + System.err.println(getThreadName()+": ALAudioSink: FLUSH playImpl "+(AL.AL_PLAYING == getSourceState())+", "+this); + } } finally { unlockContext(); - } + } } - + @Override public final int getEnqueuedFrameCount() { return enqueuedFrameCount; } - + @Override public final int getFrameCount() { return null != alBufferNames ? alBufferNames.length : 0; } - + @Override public final int getQueuedFrameCount() { if( !initialized || null == chosenFormat ) { @@ -816,7 +826,7 @@ public class ALAudioSink implements AudioSink { } return alFramesPlaying.size(); } - + @Override public final int getFreeFrameCount() { if( !initialized || null == chosenFormat ) { @@ -824,7 +834,7 @@ public class ALAudioSink implements AudioSink { } return alFramesAvail.size(); } - + @Override public final int getQueuedByteCount() { if( !initialized || null == chosenFormat ) { @@ -832,7 +842,7 @@ public class ALAudioSink implements AudioSink { } return alBufferBytesQueued; } - + @Override public final int getQueuedTime() { if( !initialized || null == chosenFormat ) { @@ -840,10 +850,10 @@ public class ALAudioSink implements AudioSink { } return chosenFormat.getBytesDuration(alBufferBytesQueued); } - + @Override public final int getPTS() { return playingPTS; } - + private static final String toHexString(int v) { return "0x"+Integer.toHexString(v); } - private static final String getThreadName() { return Thread.currentThread().getName(); } + private static final String getThreadName() { return Thread.currentThread().getName(); } } |