Audio : implemented API for seeking capability in streamed ogg files. It doesn't work fine yet
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8967 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
f3675227e0
commit
1f2193a2b9
engine/src
core/com/jme3/audio
jogg/com/jme3/audio/plugins
test/jme3test/audio
@ -448,6 +448,13 @@ public class AudioNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.timeOffset = timeOffset;
|
this.timeOffset = timeOffset;
|
||||||
|
if (data instanceof AudioStream) {
|
||||||
|
System.out.println("request setTime");
|
||||||
|
((AudioStream) data).setTime(timeOffset);
|
||||||
|
}else if(status == Status.Playing){
|
||||||
|
stop();
|
||||||
|
play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,8 @@ import com.jme3.util.NativeObject;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>AudioStream</code> is an implementation of AudioData that
|
* <code>AudioStream</code> is an implementation of AudioData that
|
||||||
@ -47,20 +49,20 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public class AudioStream extends AudioData implements Closeable{
|
public class AudioStream extends AudioData implements Closeable{
|
||||||
|
|
||||||
|
private final static Logger logger = Logger.getLogger(AudioStream.class.getName());
|
||||||
protected InputStream in;
|
protected InputStream in;
|
||||||
protected float duration = -1f;
|
protected float duration = -1f;
|
||||||
protected boolean open = false;
|
protected boolean open = false;
|
||||||
protected int[] ids;
|
protected int[] ids;
|
||||||
|
|
||||||
public AudioStream(){
|
public AudioStream(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AudioStream(int[] ids){
|
protected AudioStream(int[] ids){
|
||||||
// Pass some dummy ID so handle
|
// Pass some dummy ID so handle
|
||||||
// doesn't get created.
|
// doesn't get created.
|
||||||
super(-1);
|
super(-1);
|
||||||
|
|
||||||
// This is what gets destroyed in reality
|
// This is what gets destroyed in reality
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
}
|
}
|
||||||
@ -189,4 +191,14 @@ public class AudioStream extends AudioData implements Closeable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setTime(float time){
|
||||||
|
if(in instanceof SeekableStream){
|
||||||
|
((SeekableStream)in).setTime(time);
|
||||||
|
}else{
|
||||||
|
logger.log(Level.WARNING,"Cannot use setTime on a stream that is not seekable. You must load the file with the streamCache option set to true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
15
engine/src/core/com/jme3/audio/SeekableStream.java
Normal file
15
engine/src/core/com/jme3/audio/SeekableStream.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.audio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public interface SeekableStream{
|
||||||
|
|
||||||
|
public void setTime(float time);
|
||||||
|
|
||||||
|
}
|
@ -38,6 +38,7 @@ import com.jme3.audio.AudioBuffer;
|
|||||||
import com.jme3.audio.AudioData;
|
import com.jme3.audio.AudioData;
|
||||||
import com.jme3.audio.AudioKey;
|
import com.jme3.audio.AudioKey;
|
||||||
import com.jme3.audio.AudioStream;
|
import com.jme3.audio.AudioStream;
|
||||||
|
import com.jme3.audio.SeekableStream;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
import de.jarnbjo.ogg.EndOfOggStreamException;
|
import de.jarnbjo.ogg.EndOfOggStreamException;
|
||||||
import de.jarnbjo.ogg.LogicalOggStream;
|
import de.jarnbjo.ogg.LogicalOggStream;
|
||||||
@ -49,6 +50,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class OGGLoader implements AssetLoader {
|
public class OGGLoader implements AssetLoader {
|
||||||
|
|
||||||
@ -64,10 +67,10 @@ public class OGGLoader implements AssetLoader {
|
|||||||
private static class JOggInputStream extends InputStream {
|
private static class JOggInputStream extends InputStream {
|
||||||
|
|
||||||
private boolean endOfStream = false;
|
private boolean endOfStream = false;
|
||||||
private final VorbisStream vs;
|
protected final VorbisStream vs;
|
||||||
|
|
||||||
public JOggInputStream(VorbisStream vs){
|
public JOggInputStream(VorbisStream vs){
|
||||||
this.vs = vs;
|
this.vs = vs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -88,14 +91,25 @@ public class OGGLoader implements AssetLoader {
|
|||||||
int bytesRead = 0, cnt = 0;
|
int bytesRead = 0, cnt = 0;
|
||||||
assert length % 2 == 0; // read buffer should be even
|
assert length % 2 == 0; // read buffer should be even
|
||||||
|
|
||||||
while (bytesRead < buf.length) {
|
while (bytesRead <length) {
|
||||||
if ((cnt = vs.readPcm(buf, offset + bytesRead, buf.length - bytesRead)) <= 0) {
|
if ((cnt = vs.readPcm(buf, offset + bytesRead,length - bytesRead)) <= 0) {
|
||||||
endOfStream = true;
|
System.out.println("Read "+cnt+" bytes");
|
||||||
|
System.out.println("offset "+offset);
|
||||||
|
System.out.println("bytesRead "+bytesRead);
|
||||||
|
System.out.println("buf length "+length);
|
||||||
|
for (int i = 0; i < bytesRead; i++) {
|
||||||
|
System.out.print(buf[i]);
|
||||||
|
}
|
||||||
|
System.out.println("");
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("EOS");
|
||||||
|
endOfStream = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytesRead += cnt;
|
bytesRead += cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
swapBytes(buf, offset, bytesRead);
|
swapBytes(buf, offset, bytesRead);
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
|
|
||||||
@ -108,6 +122,36 @@ public class OGGLoader implements AssetLoader {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class SeekableJOggInputStream extends JOggInputStream implements SeekableStream {
|
||||||
|
|
||||||
|
private LogicalOggStream los;
|
||||||
|
private float duration;
|
||||||
|
|
||||||
|
public SeekableJOggInputStream(VorbisStream vs, LogicalOggStream los, float duration){
|
||||||
|
super(vs);
|
||||||
|
this.los = los;
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(float time) {
|
||||||
|
System.out.println("--setTime--)");
|
||||||
|
System.out.println("max granule : "+los.getMaximumGranulePosition());
|
||||||
|
System.out.println("current granule : "+los.getTime());
|
||||||
|
System.out.println("asked Time : "+time);
|
||||||
|
System.out.println("new granule : "+(time/duration*los.getMaximumGranulePosition()));
|
||||||
|
System.out.println("new granule2 : "+(time*vs.getIdentificationHeader().getSampleRate()));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
los.setTime((long)(time*vs.getIdentificationHeader().getSampleRate()));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(OGGLoader.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total of expected OGG bytes.
|
* Returns the total of expected OGG bytes.
|
||||||
*
|
*
|
||||||
@ -194,8 +238,12 @@ public class OGGLoader implements AssetLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream readToStream(){
|
private InputStream readToStream(boolean seekable,float streamDuration){
|
||||||
return new JOggInputStream(vorbisStream);
|
if(seekable){
|
||||||
|
return new SeekableJOggInputStream(vorbisStream,loStream,streamDuration);
|
||||||
|
}else{
|
||||||
|
return new JOggInputStream(vorbisStream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AudioData load(InputStream in, boolean readStream, boolean streamCache) throws IOException{
|
private AudioData load(InputStream in, boolean readStream, boolean streamCache) throws IOException{
|
||||||
@ -228,7 +276,7 @@ public class OGGLoader implements AssetLoader {
|
|||||||
// might return -1 if unknown
|
// might return -1 if unknown
|
||||||
float streamDuration = computeStreamDuration();
|
float streamDuration = computeStreamDuration();
|
||||||
|
|
||||||
audioStream.updateData(readToStream(), streamDuration);
|
audioStream.updateData(readToStream(oggStream.isSeekable(),streamDuration), streamDuration);
|
||||||
return audioStream;
|
return audioStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,11 @@
|
|||||||
package jme3test.audio;
|
package jme3test.audio;
|
||||||
|
|
||||||
import com.jme3.asset.AssetInfo;
|
import com.jme3.asset.AssetInfo;
|
||||||
|
import com.jme3.asset.AssetLoader;
|
||||||
import com.jme3.audio.AudioNode.Status;
|
import com.jme3.audio.AudioNode.Status;
|
||||||
import com.jme3.audio.*;
|
import com.jme3.audio.*;
|
||||||
import com.jme3.audio.plugins.OGGLoader;
|
import com.jme3.audio.plugins.OGGLoader;
|
||||||
|
import com.jme3.audio.plugins.WAVLoader;
|
||||||
import com.jme3.system.AppSettings;
|
import com.jme3.system.AppSettings;
|
||||||
import com.jme3.system.JmeSystem;
|
import com.jme3.system.JmeSystem;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -172,7 +174,13 @@ public class TestMusicPlayer extends javax.swing.JFrame {
|
|||||||
btnStopActionPerformed(null);
|
btnStopActionPerformed(null);
|
||||||
|
|
||||||
final File selected = chooser.getSelectedFile();
|
final File selected = chooser.getSelectedFile();
|
||||||
OGGLoader loader = new OGGLoader();
|
AssetLoader loader = null;
|
||||||
|
if(selected.getName().endsWith(".wav")){
|
||||||
|
loader = new WAVLoader();
|
||||||
|
}else{
|
||||||
|
loader = new OGGLoader();
|
||||||
|
}
|
||||||
|
|
||||||
AudioKey key = new AudioKey(selected.getName(), true, true);
|
AudioKey key = new AudioKey(selected.getName(), true, true);
|
||||||
try{
|
try{
|
||||||
musicData = (AudioData) loader.load(new AssetInfo(null, key) {
|
musicData = (AudioData) loader.load(new AssetInfo(null, key) {
|
||||||
@ -255,10 +263,10 @@ public class TestMusicPlayer extends javax.swing.JFrame {
|
|||||||
curTime = 0;
|
curTime = 0;
|
||||||
|
|
||||||
musicSource.setTimeOffset(curTime);
|
musicSource.setTimeOffset(curTime);
|
||||||
if (musicSource.getStatus() == Status.Playing){
|
// if (musicSource.getStatus() == Status.Playing){
|
||||||
musicSource.stop();
|
// musicSource.stop();
|
||||||
musicSource.play();
|
// musicSource.play();
|
||||||
}
|
// }
|
||||||
updateTime();
|
updateTime();
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_sldBarStateChanged
|
}//GEN-LAST:event_sldBarStateChanged
|
||||||
|
Loading…
x
Reference in New Issue
Block a user