AudioSource: add method to get playback time

As was requested on the forum, getting playback time / position is needed to perform proper audio / video synchronization.
experimental
Kirill Vainer 10 years ago
parent abc8ec0e5d
commit 7393f79165
  1. 5
      jme3-android/src/main/java/com/jme3/audio/android/AndroidMediaPlayerAudioRenderer.java
  2. 8
      jme3-core/src/main/java/com/jme3/audio/AudioNode.java
  3. 1
      jme3-core/src/main/java/com/jme3/audio/AudioRenderer.java
  4. 5
      jme3-core/src/main/java/com/jme3/audio/AudioSource.java
  5. 13
      jme3-core/src/main/java/com/jme3/audio/AudioStream.java
  6. 60
      jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java

@ -525,4 +525,9 @@ public class AndroidMediaPlayerAudioRenderer implements AudioRenderer,
@Override
public void deleteFilter(Filter filter) {
}
@Override
public float getSourcePlaybackTime(AudioSource src) {
throw new UnsupportedOperationException("Not supported yet.");
}
}

@ -410,6 +410,14 @@ public class AudioNode extends Node implements AudioSource {
}
}
@Override
public float getPlaybackTime() {
if (channel >= 0)
return getRenderer().getSourcePlaybackTime(this);
else
return 0;
}
public Vector3f getPosition() {
return getWorldTranslation();
}

@ -59,6 +59,7 @@ public interface AudioRenderer {
public void updateSourceParam(AudioSource src, AudioParam param);
public void updateListenerParam(Listener listener, ListenerParam param);
public float getSourcePlaybackTime(AudioSource src);
public void deleteFilter(Filter filter);
public void deleteAudioData(AudioData ad);

@ -96,6 +96,11 @@ public interface AudioSource {
*/
public float getTimeOffset();
/**
* @return the current playback position of the source in seconds.
*/
public float getPlaybackTime();
/**
* @return The velocity of the audio source.
*

@ -54,6 +54,8 @@ public class AudioStream extends AudioData implements Closeable {
protected boolean eof = false;
protected int[] ids;
protected int unqueuedBuffersBytes = 0;
public AudioStream() {
super();
}
@ -196,10 +198,21 @@ public class AudioStream extends AudioData implements Closeable {
return in instanceof SeekableStream;
}
public int getUnqueuedBufferBytes() {
return unqueuedBuffersBytes;
}
public void setUnqueuedBufferBytes(int unqueuedBuffers) {
this.unqueuedBuffersBytes = unqueuedBuffers;
}
public void setTime(float time) {
if (in instanceof SeekableStream) {
((SeekableStream) in).setTime(time);
eof = false;
// TODO: when we actually support seeking, this will need to be properly set.
unqueuedBuffersBytes = 0;
} else {
throw new IllegalStateException(
"Cannot use setTime on a stream that "

@ -301,6 +301,58 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
f.clearUpdateNeeded();
}
@Override
public float getSourcePlaybackTime(AudioSource src) {
checkDead();
synchronized (threadLock) {
if (audioDisabled) {
return 0;
}
// See comment in updateSourceParam().
if (src.getChannel() < 0) {
return 0;
}
int id = channels[src.getChannel()];
AudioData data = src.getAudioData();
int playbackOffsetBytes = 0;
if (data instanceof AudioStream) {
// Because audio streams are processed in buffer chunks,
// we have to compute the amount of time the stream was already
// been playing based on the number of buffers that were processed.
AudioStream stream = (AudioStream) data;
// NOTE: the assumption is that all enqueued buffers are the same size.
// this is currently enforced by fillBuffer().
// The number of unenqueued bytes that the decoder thread
// keeps track of.
int unqueuedBytes = stream.getUnqueuedBufferBytes();
// Additional processed buffers that the decoder thread
// did not unenqueue yet (it only updates 20 times per second).
int unqueuedBytesExtra = al.alGetSourcei(id, AL_BUFFERS_PROCESSED) * BUFFER_SIZE;
// Total additional bytes that need to be considered.
playbackOffsetBytes = unqueuedBytes; // + unqueuedBytesExtra;
}
// Add byte offset from source (for both streams and buffers)
playbackOffsetBytes += al.alGetSourcei(id, AL_BYTE_OFFSET);
// Compute time value from bytes
// E.g. for 44100 source with 2 channels and 16 bits per sample:
// (44100 * 2 * 16 / 8) = 176400
int bytesPerSecond = (data.getSampleRate() *
data.getChannels() *
data.getBitsPerSample() / 8);
return (float)playbackOffsetBytes / bytesPerSecond;
}
}
public void updateSourceParam(AudioSource src, AudioParam param) {
checkDead();
synchronized (threadLock) {
@ -648,6 +700,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
private boolean fillStreamingSource(int sourceId, AudioStream stream, boolean looping) {
boolean success = false;
int processed = al.alGetSourcei(sourceId, AL_BUFFERS_PROCESSED);
int unqueuedBufferBytes = 0;
for (int i = 0; i < processed; i++) {
int buffer;
@ -656,6 +709,11 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
al.alSourceUnqueueBuffers(sourceId, 1, ib);
buffer = ib.get(0);
// XXX: assume that reading from AudioStream always
// gives BUFFER_SIZE amount of bytes! This might not always
// be the case...
unqueuedBufferBytes += BUFFER_SIZE;
boolean active = fillBuffer(stream, buffer);
if (!active && !stream.isEOF()) {
@ -683,6 +741,8 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
}
}
stream.setUnqueuedBufferBytes(stream.getUnqueuedBufferBytes() + unqueuedBufferBytes);
return success;
}

Loading…
Cancel
Save